关于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中保存的请求数据,而在登录步骤提交时并不存在这些数据。
首先我们来看下我们整个流程图
这就是我自己摸索出来的关于整个访问拦截登录重定向的流程图 其中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中保存的请求数据,而在登录步骤提交时并不存在这些数据。
相关文章推荐
- 关于spring-security登录后重定向至拦截前访问的url的实现原理
- SpringBoot中实现拦截器级别的URl访问过快拦截,并利用JPA实现IP黑名单的功能。
- spring 拦截器过滤登录url 不验证是否登录其他的都拦截验证是否登录才能访问url
- 关于CAS服务端登录前ajax访问后台方法被拦截的配置-另外一种实现方式
- spring-security4.2实现登录退出以及权限配置
- spring4 security 4 +websocket 实现单点登录
- spring SecurityConfiguration中拦截url
- spring实现拦截登录请求
- CAS+Spring security实现单点登录之配置篇
- 利用Nginx负载均衡的访问SpringBoot服务,还有如何利用Nginx实现404,500等错误页面的拦截
- 关于cas-client单点登录客户端拦截请求和忽略/排除不需要拦截的请求URL的问题(不需要修改任何代码,只需要一个配置)
- 关于CAS服务端登录前ajax访问后台方法被拦截的配置
- Openfire 自定义Servlet插件访问Url登录拦截问题(源码方式)
- spring 4.1.6 中通过继承RequestMappingHandlerMapping 实现自定义url访问
- 【Spring实战】----Security4.1.3实现根据请求跳转不同登录页以及登录后根据权限跳转到不同页配置
- 关于cas-client单点登录客户端拦截请求和忽略/排除不需要拦截的请求URL的问题(不需要修改任何代码,只需要一个配置)
- Java解决在浏览器地址栏中输入url访问action的问题以及拦截方法过滤的简易实现
- Java解决在浏览器地址栏中输入url访问action的问题以及拦截方法过滤的简易实现
- Spring3.1.0实现原理分析(五).关于循环引用的探讨
- Spring3.1.0实现原理分析(五).关于循环引用的探讨