Spring BlazeDS Integration之spring security(4)---自定义rememberMeServices,找到自动登陆成功切入点
来源:互联网 发布:c .net数据库编程 编辑:程序博客网 时间:2024/06/06 05:17
我先来说一个现象,比如已经有一个使用Spring BlazeDS Integration配置了spring security的一个应用,
如下图是用户已经登录成功时,进入的界面,此时login按钮是个摆设,没有任何功能;logout按钮是通过flex提供的api是完成登出操作:
- 当,用户没有点击logout按钮,直接关闭了浏览器,浏览器比如是firefox。
- 用户再次使用firefox打开此链接的时候,
- 呈现给用户的界面依然是登陆成功的界面。
针对于此现象,我粗浅的分析了spring security的rememberMeServices源码之后分析之后,有如下结果,
关于spring security 的 Authentication处理过程大致如下:
- “用户成功登陆之后。当用户直接关闭浏览器,再重新打开浏览器访问该web的时候”:
- org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter过滤器的doFilter()会被调用.
- doFilter()方法里面,会调用当前所配置的rememberMeServices类的autoLogin(request, response)方法
- autoLogin(request, response)方法,会检测当前浏览器所传送过来的cookie信息
- 如果cookie信息没有过期,在cookie信息里面,找到key 为 "SPRING_SECURITY_REMEMBER_ME_COOKIE" 的value (spring security所设置)
- 找到value之后,使用userService,重新检索用户信息,存放在org.springframework.security.core.userdetails.UserDetails事例对象中,
- 随后,把UserDetails,转化成Authentication,至此autoLogin(request, response)方法完成: Authentication rememberMeAuth = rememberMeServices.autoLogin(request, response);
- 继续,doFilter()方法里面,会将rememberMeAuth 放入SecurityContext中去: SecurityContextHolder.getContext().setAuthentication(rememberMeAuth);
- 前台flex Gui 就是根据是否可以从SecurityContext中拿到Authentication( Authentication authentication = SecurityContextHolder.getContext().getAuthentication();) ,去判断用户是否已经登陆了。
- 总结,“用户成功登陆之后。当用户直接关闭浏览器,再重新打开浏览器访问该web的时候”:rememberMeServices会根据cookie重新setup Authentication 到SecurityContext中。
那么session的问题来了:
- “在用户成功登陆之后。当用户直接关闭浏览器,再重新打开浏览器访问该web的时候”:
- sessionId是重新创建的,session也是新创建的,log:[BlazeDS]FlexSession created with id '81E8AFF21272ECFC84A29663D8EAAB03' for an Http-based client connection.
- 这就意味着,在浏览器关闭之前的session再也找不到了,进而之前往session所放入的value也找不到了。。。
- (注意!如果是浏览器刷新操作,一般情况,session id是不会变的)
- 总结,“在用户成功登陆之后。当用户关闭浏览器,再重新打开浏览器访问该web的时候”,session会被新建,跟cookie无关,session里面是空的,没有任何曾经设置(曾经设置,是指,在用户登录成功时候往session set的value)过的properties。
整体看下来:
- “在用户成功登陆之后。当用户直接关闭浏览器,再重新打开浏览器访问该web的时候”
- Authentication 会被“复原”:因为rememberMeServices会autoLogin()
- Session会被“新建”:因为session Id 被新建,服务器无法回到原来的session
- 因此,此时所判定的用户已经登录的状态,但是session是空的,那么如果在程序中,想从session中取一些曾经设置过的properties时候,就会报错,取不到值
解决此问题的方案1:
- 在用户登录成功的时候,将session id写入cookie
- rememberMeServices调用autoLogin()的时候,读取session id,从服务器获得原始的session
解决此问题的方案2:
- 不将session id写入 cookie
- rememberMeServices调用autoLogin()的时候,其实已经创建了新的,空的session,
- 此时,再往空session设置相关的properties
我个人感觉方案2比较好一点,因为:
- “将session id写入cookie”,这个功能实现起来不难,可以在rememberMeServices.onLoginSuccess()方法里面实现。
- 但是会引发几个问题!
- cookie是有过期时间的,session也有过期时间,其两者过期时间不相同怎么办?
- cookie在浏览器会被清除的,随之的session id也就永远消失了,原始的session再也找不到怎么办?
- java api里面并不提供通过session id获得session的方法。
网上有方法,将session可以,以key-value方式存储在servletContext里面(http://www.andowson.com/posts/list/371.page),
那么如果session 过期了,是不是还得写监听方法,将其移除? - 总之方案1,会所引发的一些列问题,太麻烦了!!!
方案2的具体实现方法:
- rememberMeServices的autoLogin()方法不允许被覆盖
- autoLogin()内部会调用processAutoLoginCookie(),此方法允许被覆盖
- 可以在自定义的rememberMeServices方法中覆盖processAutoLoginCookie(),在这里为空的session重新设置相关的properties,具体实现如下
package test;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.flex.samples.product.IProductDAO;import org.springframework.security.core.Authentication;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;public class MyRememberMeServices extends TokenBasedRememberMeServices {private static final String CURRENT_NAME = "current_name";@Autowiredprivate UserDAO userDAO;@Overridepublic void onLoginSuccess(HttpServletRequest request,HttpServletResponse response,Authentication successfulAuthentication) {super.onLoginSuccess(request, response, successfulAuthentication);SecurityContextHolder.getContext().setAuthentication(successfulAuthentication);this.afterOnLoginSuccess(request, response, successfulAuthentication);}private void afterOnLoginSuccess(HttpServletRequest request,HttpServletResponse response,Authentication successfulAuthentication) {HttpSession session = request.getSession();System.out.println("login success-----------------session id = "+ session.getId());String userName = successfulAuthentication.getName();//登陆成功时,为新创建出来的空session设置properties, session.setAttribute(CURRENT_NAME, userDAO.findByUserName(userName)); }protected UserDetails processAutoLoginCookie(String[] cookieTokens,HttpServletRequest request, HttpServletResponse response) {UserDetails userDetails = super.processAutoLoginCookie(cookieTokens,request, response);this.afterProcessAutoLoginCookie(userDetails, request, response);return userDetails;}private void afterProcessAutoLoginCookie(UserDetails userDetails,HttpServletRequest request, HttpServletResponse response) {HttpSession session = request.getSession(); //之前没有session,</span>在这里会根据新的session id创建新的sessionSystem.out.println("auto login success-----------------session id = "+ session.getId());String userName = userDetails.getUsername();// 当用户已经登陆,直接关闭浏览器,再次又打开浏览器,访问该web应用时候,所走的是: “自动”登陆的流程// “自动”登陆成功时,为新创建出来的空session设置properties, session.setAttribute(CURRENT_NAME, userDAO.findByUserName(userName)); }}
在这里,我往session里面设置了数据库里面一整条的user记录,目的是让session里可以存储,user的id主键
我们要知道,Authentication对象里面是没有id主键的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
security-config.xml配置文件没有什么变化:
<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/security"xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"><http entry-point-ref="entryPoint"><anonymous enabled="false" /><form-login login-page="/login.jsp"authentication-success-handler-ref="simpleLoginSuccessHandler" /><remember-me key="testdrive" services-ref="rememberMeServices" /></http><beans:bean id="rememberMeServices" class="test.MyRememberMeServices"><beans:property name="key" value="testdrive" /><beans:property name="alwaysRemember" value="true" /></beans:bean><beans:bean id="entryPoint"class="org.springframework.flex.security3.FlexAuthenticationEntryPoint" /><beans:bean id="simpleLoginSuccessHandler" class="test.SimpleLoginSuccessHandler"><beans:property name="defaultTargetUrl" value="/secured/secured.html"></beans:property><beans:property name="forwardToDestination" value="false"></beans:property></beans:bean><authentication-manager><authentication-provider><user-service><user name="john" password="john" authorities="ROLE_USER" /><user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" /><user name="guest" password="guest" authorities="ROLE_GUEST" /></user-service></authentication-provider></authentication-manager></beans:beans>
ps:在此测试过程中,为什么始终使用同一个浏览器?原因是cookie,不同浏览器存储的cookie文件位置不同,比如fireFox的cookie路径:
- XP C:\Documents and Settings\用户名\Application Data\Mozilla\Firefox\Profiles\xxxxxxxx.default\
- Win7 C:\Users\用户名\AppData\Local\Mozilla\Firefox\Profiles
- 但是普通方式察看,都看不见该文件夹!
0 0
- Spring BlazeDS Integration之spring security(4)---自定义rememberMeServices,找到自动登陆成功切入点
- Spring BlazeDS Integration之spring security(3)---自定义rememberMeServices,找到用户登陆成功切入点
- Spring BlazeDS Integration之spring security(5)---自定义rememberMeServices的注意事项
- Spring BlazeDS Integration之spring security(1)---flex UI登陆
- Spring BlazeDS Integration之spring security(2)---http form登陆
- 案例学习BlazeDS+Spring之十五:Security Integration 101
- BlazeDS Spring Security Integration问题一点总结
- spring security自定义登陆成功后处理
- 案例学习BlazeDS+Spring之二Spring BlazeDS Integration 101
- 案例学习BlazeDS+Spring之二Spring BlazeDS Integration 101
- spring security - 自定义登陆
- Spring Blazeds integration
- Spring Security 3.1 自定义实例之登陆
- spring security 自定义登陆 - AJAX
- 使用Spring BlazeDS Integration步骤
- spring blazeDS Integration简单介绍
- spring blazeDS Integration简单介绍
- Spring BlazeDS Integration Reference Guide
- 构造模式实践
- CodeForces 510B Fox And Two Dots(图论-回路判定)
- IOS相关书签
- 宏定义
- RecyclerView的基本用法 (二)
- Spring BlazeDS Integration之spring security(4)---自定义rememberMeServices,找到自动登陆成功切入点
- 三十而立,从零开始学ios开发
- Vitamio 3.0 新手教程
- Source Insight 使用方法入门
- MTK6577---camera驱动分析
- Swift之键盘事件
- mysql 优化
- 全局块匹配法计算图像旋转以及实现程序
- WebKit in iOS 8