记住我基本原理
- 用户认证成功之后调用
RemeberMeService
根据用户名名生成Token
由TokenRepository
写入到数据库,同时也将Token
写入到浏览器的Cookie
中 - 重启服务之后,用户再次登入系统会由
RememberMeAuthenticationFilter
拦截,从Cookie
中读取Token
信息,与persistent_logins
表匹配判断是否使用记住我功能。最中由UserDetailsService
查询用户信息
记住我实现
- 创建persistent_logins表
create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null); 复制代码
- 登陆页面添加记住我复选款(name必须是remeber-me)
<input name="remember-me" type="checkbox"> 下次自动登录 复制代码
- 配置MerryyouSecurityConfig
http. ...... .and() .rememberMe() .tokenRepository(persistentTokenRepository())//设置操作表的Repository .tokenValiditySeconds(securityProperties.getRememberMeSeconds())//设置记住我的时间 .userDetailsService(userDetailsService)//设置userDetailsService .and() ...... 复制代码
效果如下
源码分析
首次登录
AbstractAuthenticationProcessingFilter#successfulAuthentication
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { if (logger.isDebugEnabled()) { logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult); } //# 1.将已认证过的Authentication放入到SecurityContext中 SecurityContextHolder.getContext().setAuthentication(authResult); //# 2.登录成功调用rememberMeServices rememberMeServices.loginSuccess(request, response, authResult); // Fire event if (this.eventPublisher != null) { eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent( authResult, this.getClass())); } successHandler.onAuthenticationSuccess(request, response, authResult); } 复制代码
- 将已认证过的Authentication放入到SecurityContext中
- 登录成功调用rememberMeServices
AbstractRememberMeServices#loginSuccess
private String parameter = DEFAULT_PARAMETER;//remember-me public final void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { // #1.判断是否勾选记住我 if (!rememberMeRequested(request, parameter)) { logger.debug("Remember-me login not requested."); return; } onLoginSuccess(request, response, successfulAuthentication); } 复制代码
- 判断是否勾选记住我
PersistentTokenBasedRememberMeServices#onLoginSuccess
protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { //#1.获取用户名 String username = successfulAuthentication.getName(); logger.debug("Creating new persistent login for user " + username); //#2.创建Token PersistentRememberMeToken persistentToken = new PersistentRememberMeToken( username, generateSeriesData(), generateTokenData(), new Date()); try { //#3.存储都数据库 tokenRepository.createNewToken(persistentToken); //#4.写入到浏览器的Cookie中 addCookie(persistentToken, request, response); } catch (Exception e) { logger.error("Failed to save persistent token ", e); } } 复制代码
- 获取用户名
- 创建Token
- 存储都数据库
- 写入到浏览器的Cookie中
二次登录Remember-me
RememberMeAuthenticationFilter#doFilter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; //#1.判断SecurityContext中没有Authentication if (SecurityContextHolder.getContext().getAuthentication() == null) { //#2.从Cookie查询用户信息返回RememberMeAuthenticationToken Authentication rememberMeAuth = rememberMeServices.autoLogin(request, response); if (rememberMeAuth != null) { // Attempt authenticaton via AuthenticationManager try { //#3.如果不为空则由authenticationManager认证 rememberMeAuth = authenticationManager.authenticate(rememberMeAuth); // Store to SecurityContextHolder SecurityContextHolder.getContext().setAuthentication(rememberMeAuth); onSuccessfulAuthentication(request, response, rememberMeAuth); ...... 复制代码
- 判断SecurityContext中没有Authentication
- 从Cookie查询用户信息返回RememberMeAuthenticationToken
- 如果不为空则由authenticationManager认证
AbstractRememberMeServices#autoLogin
public final Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) { //#1.获取Cookie String rememberMeCookie = extractRememberMeCookie(request); if (rememberMeCookie == null) { return null; } logger.debug("Remember-me cookie detected"); if (rememberMeCookie.length() == 0) { logger.debug("Cookie was empty"); cancelCookie(request, response); return null; } UserDetails user = null; try { //#2.解析Cookie String[] cookieTokens = decodeCookie(rememberMeCookie); //#3.获取用户凭证 user = processAutoLoginCookie(cookieTokens, request, response); //#4.检查用户凭证 userDetailsChecker.check(user); logger.debug("Remember-me cookie accepted"); //#5.返回Authentication 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; } 复制代码
- 获取Cookie
- 解析Cookie
- 获取用户凭证
- 检查用户凭证
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 记住变量类型的三种方式
- Android-保你能记住的生命周期教程
- springboot + shiro 验证码与记住登录
- 谷歌最新举动:安卓用户无需再记住密码
- Angular APP开发时要记住的事项
- 您真的记住了吗?游戏知识速记卡・第二期
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux/Unix设计思想
甘卡兹 / 漆犇 / 人民邮电出版社 / 2012-3-28 / 39.00元
《Linux\Unix设计思想/图灵程序设计丛书》内容简介:将Linux的开发方式与Unix的原理有效地结合起来,总结出Linux与Unix软件开发中的设计原则。《Linux\Unix设计思想/图灵程序设计丛书》前8章分别介绍了Linux与Unix中9条基本的哲学准则和10条次要准则。第9章和第10章将Unix系统的设计思想与其他系统的设计思想进行了对比。最后介绍了Unix哲学准则在其他领域中的应......一起来看看 《Linux/Unix设计思想》 这本书的介绍吧!
图片转BASE64编码
在线图片转Base64编码工具
HSV CMYK 转换工具
HSV CMYK互换工具