您的位置:首页 > 编程语言 > Java开发

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

2016-11-24 14:21 686 查看
http://blog.csdn.net/zy_cookie/article/details/49535413

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



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



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

[java]
view plain
copy

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

[align=left]2.[/align]
我们能够看出当其在身份的权限验证失败的情况下会抛出accessDeniedException异常,这个时候上一层的拦截器也就是倒数第二个拦截器ExceptionTranslationFilter捕获了该异常并进一步处理具体代码如下

[java]
view plain
copy

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);  
        }  
    }  
}  

[align=left]3.[/align]
[align=left]进入sendStartAuthentication这个函数后我们看到了[/align]

[java]
view plain
copy

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 );  
}  

[align=left]这里就有requestCache.saveRequest(request,response);对对象进行保存的业务代码。这个是保存的key[/align]
[align=left]staticfinalStringSAVED_REQUEST="SPRING_SECURITY_SAVED_REQUEST";[/align]
[align=left]6.[/align]
登录请求验证完成之后 UsernamePasswordAuthenticationFilter会调用SavedRequestAwareAuthenticationSuccessHandler的实例loginsuccesshandler来处理登录成功后的处理步骤
   publicvoidonAuthenticationSuccess(HttpServletRequestrequest,
HttpServletResponseresponse,
            Authenticationauthentication)throwsServletException,
IOException {
        SavedRequestsavedRequest
=
requestCache.getRequest(request,response);
[align=left]
[/align]
       if(savedRequest==null)
{
[align=left]           super.onAuthenticationSuccess(request,response,authentication);[/align]
[align=left]
[/align]
[align=left]           return;[/align]
[align=left]        }[/align]
        StringtargetUrlParameter=
getTargetUrlParameter();
       if(isAlwaysUseDefaultTargetUrl()
|| (targetUrlParameter!=null&&
StringUtils.hasText(request.getParameter(targetUrlParameter))))
{
[align=left]           requestCache.removeRequest(request,response);[/align]
[align=left]           super.onAuthenticationSuccess(request,response,authentication);[/align]
[align=left]
[/align]
[align=left]           return;[/align]
[align=left]        }[/align]
[align=left]
[/align]
[align=left]        clearAuthenticationAttributes(request);[/align]
[align=left]
[/align]
[align=left]       // Use the DefaultSavedRequest URL[/align]
[align=left]        StringtargetUrl=savedRequest.getRedirectUrl();[/align]
       logger.debug("Redirecting
to DefaultSavedRequest Url: "+targetUrl);
[align=left]        getRedirectStrategy().sendRedirect(request,response,targetUrl);[/align]
[align=left]    }[/align]
我们在这里看到该方法从session中获取缓存的拦截前request对象,并进行除重定向之外无其他的操作
7.
我们看到 RequestCacheAwareFilter在拦截器链中排第7位,它的作用就是获取session中的保存的request并对当前的request进行替换工作

[java]
view plain
copy

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中保存的请求数据,而在登录步骤提交时并不存在这些数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐