springSecurity的两种rememberMe方式 springSecurity 使用RememberMeAuthenticationFilter处理记住我功能,代码逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public  void  doFilter (ServletRequest req, ServletResponse res, FilterChain chain) throws  IOException, ServletException {HttpServletRequest  request  =  (HttpServletRequest) req;HttpServletResponse  response  =  (HttpServletResponse) res;if  (SecurityContextHolder.getContext().getAuthentication() == null ) {Authentication  rememberMeAuth  =  rememberMeServices.autoLogin(request,response);if  (rememberMeAuth != null ) {try  {if  (successHandler != null ) {return ;catch  (AuthenticationException authenticationException) {else  {
springSeciruity提供的实现 上面的filter使用RememberMeServices来处理自动登录,
TokenBasedRememberMeServices和PersistentTokenBasedRememberMeServices是springSecurity提供的两种处理remenberMe的实现类
他俩都继承自 AbstractRememberMeServices
0.AbstractRememberMeServices 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public  final  Authentication  autoLogin (HttpServletRequest  request ,HttpServletResponse  response ) {String  rememberMeCookie  =  extractRememberMeCookie (request );UserDetails  user  =  null ;try  {String [] cookieTokens  =  decodeCookie (rememberMeCookie );user  =  processAutoLoginCookie (cookieTokens , request , response );userDetailsChecker .check (user );return  createSuccessfulAuthentication (request , user );catch  (CookieTheftException  cte ) {cancelCookie (request , response );throw  cte ;catch  (UsernameNotFoundException  noUser ) {logger .debug ("Remember-me login was valid but corresponding user not found." ,noUser );catch  (InvalidCookieException  invalidCookie) {logger .debug ("Invalid remember-me cookie: "  +  invalidCookie.getMessage ());catch  (AccountStatusException  statusInvalid ) {logger .debug ("Invalid UserDetails: "  +  statusInvalid .getMessage ());catch  (RememberMeAuthenticationException  e ) {logger .debug (e .getMessage ());cancelCookie (request , response );return  null ;
1. 使用TokenBasedRememberMeServices如何实现processAutoLoginCookie方法的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 protected  UserDetails  processAutoLoginCookie (String [] cookieTokens,			HttpServletRequest  request, HttpServletResponse  response ) {if  (cookieTokens.length  != 3 ) {throw  new  InvalidCookieException ("Cookie token did not contain 3" " tokens, but contained '"  + Arrays .asList (cookieTokens) + "'" );try  {new  Long (cookieTokens[1 ]).longValue ();catch  (NumberFormatException  nfe) {throw  new  InvalidCookieException ("Cookie token[1] did not contain a valid number (contained '" 1 ] + "')" );if  (isTokenExpired (tokenExpiryTime)) {throw  new  InvalidCookieException ("Cookie token[1] has expired (expired on '" new  Date (tokenExpiryTime) + "'; current time is '"  + new  Date ()"')" );UserDetails  userDetails = getUserDetailsService ().loadUserByUsername (0 ]);String  expectedTokenSignature = makeTokenSignature (tokenExpiryTime,getUsername (), userDetails.getPassword ());if  (!equals (expectedTokenSignature, cookieTokens[2 ])) {throw  new  InvalidCookieException ("Cookie token[2] contained signature '" 2 ] + "' but expected '"  + expectedTokenSignature + "'" );return  userDetails;
上面的方法就是根据cookie中查询的用户名到数据库中查询出真实用户信息。根据真实的信息,构造出签名与cookie中的签名进行比较。
这样可以防止cookie伪造,但不能防止cookie被别人窃取使用。
2. 使用PersistentTokenBasedRememberMeServices如何实现processAutoLoginCookie方法的 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 protected  UserDetails processAutoLoginCookie (String[] cookieTokens, 			HttpServletRequest request, HttpServletResponse response)  {if  (cookieTokens.length != 2 ) {throw  new  InvalidCookieException ("Cookie token did not contain "  + 2 " tokens, but contained '"  + Arrays.asList(cookieTokens) + "'" );final  String  presentedSeries  =  cookieTokens[0 ];final  String  presentedToken  =  cookieTokens[1 ];PersistentRememberMeToken  token  =  tokenRepositoryif  (token == null ) {throw  new  RememberMeAuthenticationException ("No persistent token found for series id: "  + presentedSeries);if  (!presentedToken.equals(token.getTokenValue())) {throw  new  CookieTheftException ("PersistentTokenBasedRememberMeServices.cookieStolen" ,"Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack." ));if  (token.getDate().getTime() + getTokenValiditySeconds() * 1000L  < Systemthrow  new  RememberMeAuthenticationException ("Remember-me login has expired" );PersistentRememberMeToken  newToken  =  new  PersistentRememberMeToken (new  Date ());try  {catch  (Exception e) {"Failed to update token: " , e);throw  new  RememberMeAuthenticationException ("Autologin failed due to data access problem" );return  getUserDetailsService().loadUserByUsername(token.getUsername());
这个rememberMeServices的处理逻辑是,每次自动登录成功后将cookie中的某个随机值和数据库同步更新,假设cookie别别人盗用,自动登录后盗用者的cookie被更新了。
主人的cookie就会变无效。下次主人会自动登录失败,系统就能发现cookie被盗用,此时删除数据库中的对应cookie验证,通知用户改密码等.