Spring Security Web 5.1.2 源码解析 — SimpleUrlAuthenticationFailureHandler

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

概述

AuthenticationFailureHandler接口定义了Spring Security Web在遇到认证错误时所使用的处理策略。

典型做法一般是将用户重定向到认证页面(比如认证机制是用户名表单认证的情况)让用户再次认证。当然具体实现类可以根据需求实现更复杂的逻辑,比如根据异常做不同的处理等等。举个例子,如果遇到CredentialsExpiredException异常(AuthenticationException异常的一种,表示密码过期失效),可以将用户重定向到修改密码页面而不是登录认证页面。

该接口定义如下 :

    package org.springframework.security.web.authentication;

    public interface AuthenticationFailureHandler {

        /** * 认证失败时会调用此方法 * @param request 出现认证失败时所处于的请求. * @param response 对应上面请求的响应对象. * @param exception 携带认证失败原因的认证失败异常对象 * request. */
        void onAuthenticationFailure(HttpServletRequest request,
                HttpServletResponse response, AuthenticationException exception)
                throws IOException, ServletException;
    }

Spring Security Web框架内部,缺省使用的认证错误处理策略是AuthenticationFailureHandler的实现类SimpleUrlAuthenticationFailureHandler。它由配置指定一个defaultFailureUrl,表示认证失败时缺省使用的重定向地址。一旦认证失败,它的方法onAuthenticationFailure被调用时,它就会将用户重定向到该地址。如果该属性没有设置,它会向客户端返回一个401状态码。另外SimpleUrlAuthenticationFailureHandler还有一个属性useForward,如果该属性设置为true,页面跳转将不再是重定向(redirect)机制,取而代之的是转发(forward)机制。

源代码解析

具体实现代码如下 :

    package org.springframework.security.web.authentication;

    public class SimpleUrlAuthenticationFailureHandler implements
            AuthenticationFailureHandler {
        protected final Log logger = LogFactory.getLog(getClass());

        // 认证失败时缺省使用的重定向地址
        private String defaultFailureUrl;
        // 是否使用 forward, 缺省为 false, 表示使用 redirect
        private boolean forwardToDestination = false;
        // 是否在需要session的时候允许创建session
        private boolean allowSessionCreation = true;
        // 页面重定向策略
        private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

        public SimpleUrlAuthenticationFailureHandler() {
        }

        public SimpleUrlAuthenticationFailureHandler(String defaultFailureUrl) {
            setDefaultFailureUrl(defaultFailureUrl);
        }

        /** * Performs the redirect or forward to the defaultFailureUrl if set, otherwise * returns a 401 error code. * * If redirecting or forwarding, saveException will be called to cache the * exception for use in the target view. */
        public void onAuthenticationFailure(HttpServletRequest request,
                HttpServletResponse response, AuthenticationException exception)
                throws IOException, ServletException {

            if (defaultFailureUrl == null) {
                logger.debug("No failure URL set, sending 401 Unauthorized error");

                // 如果 defaultFailureUrl 没有设置,向客户端返回 401 错误 : Unauthorized
                response.sendError(HttpStatus.UNAUTHORIZED.value(),
                    HttpStatus.UNAUTHORIZED.getReasonPhrase());
            }
            else {
                saveException(request, exception);

                if (forwardToDestination) {
                    // 指定了使用 forward 的情况
                    logger.debug("Forwarding to " + defaultFailureUrl);

                    request.getRequestDispatcher(defaultFailureUrl)
                            .forward(request, response);
                }
                else {
                    // 指定了使用 redirect 的情况 , 缺省情况
                    logger.debug("Redirecting to " + defaultFailureUrl);
                    redirectStrategy.sendRedirect(request, response, defaultFailureUrl);
                }
            }
        }

        /** * Caches the AuthenticationException for use in view rendering. * * If forwardToDestination is set to true, request scope will be used, * otherwise it will attempt to store the exception in the session. If there is no * session and allowSessionCreation is true a session will be created. * Otherwise the exception will not be stored. */
        protected final void saveException(HttpServletRequest request,
                AuthenticationException exception) {
            if (forwardToDestination) {
            // forward 的情况,保存异常到 request 属性 : SPRING_SECURITY_LAST_EXCEPTION
                request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
            }
            else {
            // redirect 的情况 , 保存异常到 session : SPRING_SECURITY_LAST_EXCEPTION
                HttpSession session = request.getSession(false);

                if (session != null || allowSessionCreation) {
                    request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION,
                            exception);
                }
            }
        }

        /** * The URL which will be used as the failure destination. * * @param defaultFailureUrl the failure URL, for example "/loginFailed.jsp". */
        public void setDefaultFailureUrl(String defaultFailureUrl) {
            Assert.isTrue(UrlUtils.isValidRedirectUrl(defaultFailureUrl),
                    () -> "'" + defaultFailureUrl + "' is not a valid redirect URL");
            this.defaultFailureUrl = defaultFailureUrl;
        }

        protected boolean isUseForward() {
            return forwardToDestination;
        }

        /** * If set to true, performs a forward to the failure destination URL instead * of a redirect. Defaults to false. */
        public void setUseForward(boolean forwardToDestination) {
            this.forwardToDestination = forwardToDestination;
        }

        /** * Allows overriding of the behaviour when redirecting to a target URL. */
        public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
            this.redirectStrategy = redirectStrategy;
        }

        protected RedirectStrategy getRedirectStrategy() {
            return redirectStrategy;
        }

        protected boolean isAllowSessionCreation() {
            return allowSessionCreation;
        }

        public void setAllowSessionCreation(boolean allowSessionCreation) {
            this.allowSessionCreation = allowSessionCreation;
        }
    }

应用位置

  1. FormLoginConfigurer基类AbstractAuthenticationFilterConfigurer
        // 表单认证安全配置阶段指定 failureHandler
        // 缺省情况下,这里 authenticationFailureUrl 是 /login?error
        public final T failureUrl(String authenticationFailureUrl) {
            T result = failureHandler(new SimpleUrlAuthenticationFailureHandler(
                    authenticationFailureUrl));
            this.failureUrl = authenticationFailureUrl;
            return result;
        }
  1. UsernamePasswordAuthenticationFilter基类AbstractAuthenticationProcessingFilter
    // 在 UsernamePasswordAuthenticationFilter 对象创建时的初始值,不过一般
    // 该初始值都会被安全配置中的 failureHandler 覆盖
    private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
  1. SessionManagementFilter
    SessionManagementFilter在针对认证成功时如果执行有关session策略逻辑失败,也会认为是认证失败,从而需要一个AuthenticationFailureHandler
    private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

参考文章

Spring Security Web 5.1.2 源码解析 – 框架缺省使用的页面重定向策略


来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Security Web 5.1.2 源码解析 — SimpleUrlAuthenticationFailureHandler

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏