Spring Security登录返回登录前请求地址功能

Spring Security登录返回登录前请求地址功能

以下部分描述内容来自Spring Security 3.1官方文档9.1章的个人翻译

Spring Security过滤器链的倒数第三层ExceptionTranslationFilter完成以下三个工作:

在用户请求一个受保护资源用户未认证或未授权时,一个对应的AuthenticationException或AccessDeniedException异常会被抛出。

1) 如果用户未认证AuthenticationException异常会交给内置的AuthenticationEntryPoint实现处理,以返回合适的响应(如HTTP错误码)给用户。默认的LoginUrlAuthenticationEntryPoint会将请求重定向到预设的url上;

2) 如果用户认证但未授权AccessDeniedException异常则有两种情况,如果是匿名用户,仍视为是用户未认证,交给AuthenticationEntryPoint处理,否则会交给内置的AccessDeniedHandler处理,默认情况下他是返回一个HTTP状态码为403的响应,但也可以配置相应的url进行重定向;

3) 在调用AuthenticationEntryPoint处理之前,ExceptionTranslationFilter会将当前请求的相关数据封装为SavedRequest对象保存到RequestCache中,以供登录后获取,默认的实现为HttpSessionRequestCache即将数据保存到HttpSession中。

上述功能在<security:http auto-config="true">时会自动部署一套通用的配置,相关对象会作为Spring上下文中的Bean。


上述描述中本文最为重要的是第三点,实际上我们的页面处理类只需要获取到这个RequestCache对象,即可拿到在跳往登录程序之前的请求数据。以下示例虽然是基于Spring MVC,但Spring Security在Web工程中,是作为Filter存在,任何的MVC框架只要知道原理一样能实现相同的功能。

如下的Spring Security配置:

<security:http auto-config="true" authentication-manager-ref="authenticationManager">    <!-- 登录页面 -->    <security:form-login login-page="/login.html"/>    <!-- 其他配置 -->    <!-- ... --></security:http>

我们在登录页面login.html及登录过程login.do的处理器Bean中声明注入RequestCache,默认情况下Spring上下文里面只会有一个RequestCache实例。如果不是Spring MVC,使用其他的MVC框架需要自己想办法从Spring应用程序上下文获取到RequestCache实例。

private RequestCache requestCache = null; @Required@Resourcepublic void setRequestCache(RequestCache requestCache) {    this.requestCache = requestCache;}

这样在login.do的处理过程中,我们可以用当前请求的request和response对象从RequestCache中获取保存的SavedRequest实例。如果不是Spring MVC,使用其他的MVC框架需要自己想办法获取到request和response对象。

SavedRequest savedRequest = requestCache.getRequest(request, response);// 默认的重定向地址String redirectUrl = "/index.html";// 注意1 如果用户直接访问login.html,这时候ExceptionTranslationFilter不会有任何操作,SavedRequest可能为null// 注意2 只有GET请求才会说进行重定向,如果原请求为POST等,没有重定向的价值,仍使用默认的重定向地址if (savedRequest != null) {    if("GET".equals(savedRequest.getMethod())) {        redirectUrl = savedRequest.getRedirectUrl();    }    // 最后记得删除requestCache    // 注意这里的removeRequest传入的参数仍然是当前的request和response对象    requestCache.removeRequest(request, response);}// 重定向到目标地址,这个是Spring MVC的写法,其他的MVC框架请采用各自自己的做法return "redirect:" + redirectUrl;

当然知道这样,仍然是不够的,如果我们不想把信息保存在session里面怎么办,如果我们希望在用户未认证或用户未授权访问受保护资源的时候做更多的事情怎么办(做个日志记录下不为过吧)。这时候我们可以自己实现自己的AuthenticationEntryPoint,AccessDeniedHandler和RequestCache,自己在Spring上下文中,使用Spring Security的机制替换默认存在的ExceptionTranslationFilter。(注意这样的情况Spring上下文中可能有多个RequestCache实例,最好自定义bean的时候给予一个特殊的beanName,指定bean名注入需要的RequestCache)

<security:custom-filter ref="myExceptionTranslationFilter" position="EXCEPTION_TRANSLATION_FILTER"/>

推荐阅读