关于spring-security登录后重定向至拦截前访问的url的实现原理

首先我们来看下我们整个流程图

关于spring-security登录后重定向至拦截前访问的url的实现原理_第1张图片

这就是我自己摸索出来的关于整个访问拦截登录重定向的流程图 其中3,6,7步是对拦截前访问的request的处理
接下来是对以上几个步骤中关键代码的分析
1.
首先我们先了解下关于 FilterSecurityIntercepto所在的位置

关于spring-security登录后重定向至拦截前访问的url的实现原理_第2张图片

我们看到他在最后一位从这个拦截器的下面代码:

        // Attempt authorization
        try {
            this.accessDecisionManager .decide(authenticated , object , attributes );
        }
        catch (AccessDeniedException accessDeniedException ) {
            publishEvent( new AuthorizationFailureEvent(object , attributes , authenticated, accessDeniedException ));

            throw accessDeniedException;
        }

2.
我们能够看出当其在身份的权限验证失败的情况下会抛出 accessDeniedException异常,这个时候上一层的拦截器也就是倒数第二个拦截器ExceptionTranslationFilter捕获了该异常并进一步处理具体代码如下
    private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response , FilterChain chain,
            RuntimeException exception) throws IOException, ServletException {
        if (exception instanceof AuthenticationException) {
            logger.debug( "Authentication exception occurred; redirecting to authentication entry point", exception);

            sendStartAuthentication( request, response, chain, (AuthenticationException) exception );
        }
        else if (exception instanceof AccessDeniedException ) {
            if (authenticationTrustResolver .isAnonymous(SecurityContextHolder.getContext().getAuthentication())) {
                logger.debug( "Access is denied (user is anonymous); redirecting to authentication entry point",
                            exception);

                sendStartAuthentication( request, response, chain, new InsufficientAuthenticationException(
                        "Full authentication is required to access this resource"));
            }
            else {
                logger.debug( "Access is denied (user is not anonymous); delegating to AccessDeniedHandler", exception);

                accessDeniedHandler.handle(request , response , (AccessDeniedException) exception);
            }
        }
    }
3.
进入 sendStartAuthentication这个函数后我们看到了
    protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response , FilterChain chain,
            AuthenticationException reason) throws ServletException, IOException {
        // SEC-112: Clear the SecurityContextHolder's Authentication, as the
        // existing Authentication is no longer considered valid
        SecurityContextHolder. getContext().setAuthentication(null);
        requestCache.saveRequest(request , response );
        logger.debug( "Calling Authentication entry point." );
        authenticationEntryPoint.commence(request , response , reason );
    }
这里就有 requestCache .saveRequest( request , response );对对象进行保存的业务代码。这个是保存的key
static final String SAVED_REQUEST = "SPRING_SECURITY_SAVED_REQUEST" ;

6.
登录请求验证完成之后 UsernamePasswordAuthenticationFilter会调用 SavedRequestAwareAuthenticationSuccessHandler 的实例loginsuccesshandler来处理登录成功后的处理步骤
    public void onAuthenticationSuccess(HttpServletRequest request , HttpServletResponse response ,
            Authentication authentication ) throws ServletException, IOException {
        SavedRequest savedRequest = requestCache .getRequest( request , response );

        if ( savedRequest == null ) {
            super .onAuthenticationSuccess( request , response , authentication );

            return ;
        }
        String targetUrlParameter = getTargetUrlParameter();
        if (isAlwaysUseDefaultTargetUrl() || ( targetUrlParameter != null && StringUtils.hasText( request .getParameter( targetUrlParameter )))) {
            requestCache .removeRequest( request , response );
            super .onAuthenticationSuccess( request , response , authentication );

            return ;
        }

        clearAuthenticationAttributes( request );

        // Use the DefaultSavedRequest URL
        String targetUrl = savedRequest .getRedirectUrl();
        logger .debug( "Redirecting to DefaultSavedRequest Url: " + targetUrl );
        getRedirectStrategy().sendRedirect( request , response , targetUrl );
    }
我们在这里看到该方法从session中获取缓存的拦截前request对象,并进行除重定向之外无其他的操作

7.
我们看到 RequestCacheAwareFilter在拦截器链中排第7位,它的作用就是获取session中的保存的request并对当前的request进行替换工作
    public void doFilter(ServletRequest request , ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest wrappedSavedRequest =
            requestCache.getMatchingRequest((HttpServletRequest) request, (HttpServletResponse)response );

        chain.doFilter( wrappedSavedRequest == null ? request : wrappedSavedRequest, response );
    }
这个方法中很明显继续下面拦截处理的request已经不是之前的那个request的对象了而是被替换成了继承自 HttpServletRequestWrapper的 SavedRequestAwareWrapper。
这时我们已经清楚的发现新的request已经带上了我们被拦截前的request中保存的请求数据,而在登录步骤提交时并不存在这些数据。





你可能感兴趣的:(领悟,java,spring)