首页 > 解决方案 > JAVA - 自定义过滤器验证失败后如何重定向到登录页面?

问题描述

我必须在 Spring-security 的验证过程中添加一些额外的验证。我在配置 xml 中添加了“自定义过滤器”,但是当它失败时将我重定向到错误页面,而不是登录页面。我可以毫无问题地访问我的“authenticationFilter”类,并且当我的凭据良好并进入主页面时我没有问题。

我的 Spring-security 配置是:

<http auto-config="true" use-expressions="true">
    <intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
    <intercept-url pattern="/login" access="permitAll" />
    <intercept-url pattern="/**" access="isAuthenticated()" />

    <custom-filter 
        ref="authenticationFilter" 
            before="FORM_LOGIN_FILTER"
    />
    <!-- access denied page -->
    <access-denied-handler error-page="/403" />
    <form-login 
        login-page="/login" 
        default-target-url="/home"
        authentication-failure-url="/login?error" 
        username-parameter="username"
        password-parameter="password"
    />
    <logout logout-success-url="/login?logout" />
</http>

我的过滤器是:

@Component("authenticationFilter")
public class RequestBodyReaderAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private static final Log LOG = LogFactory.getLog(RequestBodyReaderAuthenticationFilter.class);

    private static final String ERROR_MESSAGE = "Error en la validación con AD";

    private final ObjectMapper objectMapper = new ObjectMapper();

    public RequestBodyReaderAuthenticationFilter() {
    }

    @Autowired
    @Qualifier("authenticationManager")
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String requestBody;
        Boolean valido = false;
        try {
            requestBody = IOUtils.toString(request.getReader());
            ArrayList<String> credenciales = new ArrayList<String>();
            for (String val : requestBody.split("&")) {
                credenciales.add(val.split("=")[1]);
            }

            try {
                org.tempuri.ADWS service = new org.tempuri.ADWS();
                org.tempuri.IADWS port = service.getBasicHttpBindingIADWS();

                valido = port.login(credenciales.get(0), credenciales.get(1));
            } catch (Exception ex) {
                LOG.error(ERROR_MESSAGE, ex);
            }
            UsernamePasswordAuthenticationToken token;
            if (valido) {
                token = new UsernamePasswordAuthenticationToken(credenciales.get(0), credenciales.get(1));
                setDetails(request, token);
            } else {
                LOG.error("El usuario " + credenciales.get(0) + " no existe en AD");
                token = new UsernamePasswordAuthenticationToken("", "");
                setDetails(request, token);
            }
            return this.getAuthenticationManager().authenticate(token);
        } catch (IOException e) {
            LOG.error(ERROR_MESSAGE, e);
            throw new InternalAuthenticationServiceException(ERROR_MESSAGE, e);
        } catch (Exception e) {
            LOG.error(ERROR_MESSAGE, e);
            throw new InternalAuthenticationServiceException(ERROR_MESSAGE, e);
        }
    }

}

我需要当“自定义过滤器”的验证失败时,它会重定向到登录页面,而不是抛出 401/403 默认页面。

标签: javaspringspring-securityconfiguration

解决方案


最后我找到了解决我的问题的方法。我为类 RequestBodyReaderAuthenticationFilter 覆盖方法 unsuccessfulAuthentication,并重定向到我的登录错误页面。

我做了很多证明,在所有情况下,这都是成功的。

现在的课是:

    @Component("authenticationFilter")
    public class RequestBodyReaderAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

        private static final Log LOG = LogFactory.getLog(RequestBodyReaderAuthenticationFilter.class);
        private static final String ERROR_MESSAGE = "Error en la validación con AD";
        private final ObjectMapper objectMapper = new ObjectMapper();
        public RequestBodyReaderAuthenticationFilter() {
        }

        @Autowired
        @Qualifier("authenticationManager")
        @Override
        public void setAuthenticationManager(AuthenticationManager authenticationManager) {
            super.setAuthenticationManager(authenticationManager);
        }

        @Override
        protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
            LOG.error("El usuario no existe en AD");
            response.sendRedirect(request.getContextPath()+"/login?error"); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
            String requestBody;
            Boolean valido = false;
            try {
                requestBody = IOUtils.toString(request.getReader());
                ArrayList<String> credenciales = new ArrayList<String>();
                //Busco el Usu y pass enviados en el request
                for (String val : requestBody.split("&")) {
                    credenciales.add(val.split("=")[1]);
                }

                try {
                    //hago el llamado el WS
                    org.tempuri.ADWS service = new org.tempuri.ADWS();
                    org.tempuri.IADWS port = service.getBasicHttpBindingIADWS();

                    valido = port.login(credenciales.get(0), credenciales.get(1));
                } catch (Exception ex) {
                    LOG.error(ERROR_MESSAGE, ex);
                }
                UsernamePasswordAuthenticationToken token;
                if (valido) {
                    //si existe en AD, realizo la validación en el sistema
                    token = new UsernamePasswordAuthenticationToken(credenciales.get(0), credenciales.get(1));
                    setDetails(request, token);
                    return this.getAuthenticationManager().authenticate(token);
                }else{
                    throw new InternalAuthenticationServiceException(ERROR_MESSAGE);                
                }
            } catch (IOException e) {
                LOG.error(ERROR_MESSAGE, e);
                throw new InternalAuthenticationServiceException(ERROR_MESSAGE, e);
            }
        }
    }

推荐阅读