千家信息网

SpringSecurityRememberme使用及原理是什么

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,SpringSecurityRememberme使用及原理是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Remember me
千家信息网最后更新 2026年11月04日SpringSecurityRememberme使用及原理是什么

SpringSecurityRememberme使用及原理是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

Remember me功能就是勾选"记住我"后,一次登录,后面在有效期内免登录。

先看具体配置:

pom文件:

org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-security

Security的配置:

@Autowired private UserDetailsService myUserDetailServiceImpl; // 用户信息服务 @Autowired private DataSource dataSource; // 数据源 @Override protected void configure(HttpSecurity http) throws Exception { // formLogin()是默认的登录表单页,如果不配置 loginPage(url),则使用 spring security // 默认的登录页,如果配置了 loginPage()则使用自定义的登录页 http.formLogin() // 表单登录 .loginPage(SecurityConst.AUTH_REQUIRE) .loginProcessingUrl(SecurityConst.AUTH_FORM) // 登录请求拦截的url,也就是form表单提交时指定的action .successHandler(loginSuccessHandler) .failureHandler(loginFailureHandler) .and() .rememberMe() .userDetailsService(myUserDetailServiceImpl) // 设置userDetailsService .tokenRepository(persistentTokenRepository()) // 设置数据访问层 .tokenValiditySeconds(60 * 60) // 记住我的时间(秒) .and() .authorizeRequests() // 对请求授权 .antMatchers(SecurityConst.AUTH_REQUIRE, securityProperty.getBrowser().getLoginPage()).permitAll() // 允许所有人访问login.html和自定义的登录页 .anyRequest() // 任何请求 .authenticated()// 需要身份认证 .and() .csrf().disable() // 关闭跨站伪造 ; } /** * 持久化token * * Security中,默认是使用PersistentTokenRepository的子类InMemoryTokenRepositoryImpl,将token放在内存中 * 如果使用JdbcTokenRepositoryImpl,会创建表persistent_logins,将token持久化到数据库 */ @Bean public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl(); tokenRepository.setDataSource(dataSource); // 设置数据源// tokenRepository.setCreateTableOnStartup(true); // 启动创建表,创建成功后注释掉 return tokenRepository; }

上面的myUserDetailServiceImpl是自己实现的UserDetailsService接口,dataSource会自动读取数据库配置。过期时间设置的3600秒,即一个小时

在登录页面加一行(name必须是remeber-me):

"记住我"基本原理:

1、第一次发送认证请求,会被UsernamePasswordAuthenticationFilter拦截,然后身份认证。

认证成功后,在AbstracAuthenticationProcessingFilter中,有个RememberMeServices接口。

该接口默认实现类是NullRememberMeServices,这里会调用另一个实现抽象类AbstractRememberMeServices

// ... private RememberMeServices rememberMeServices = new NullRememberMeServices(); protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { // ... SecurityContextHolder.getContext().setAuthentication(authResult); // 登录成功后,调用RememberMeServices保存Token相关信息 rememberMeServices.loginSuccess(request, response, authResult); // ... }

2、调用AbstractRememberMeServices的loginSuccess方法。

可以看到如果request中name为"remember-me"为true时,才会调用下面的onLoginSuccess()方法。这也是为什么上面登录页中的表单,name必须是"remember-me"的原因:

3、在Security中配置了rememberMe()之后, 会由PersistentTokenBasedRememberMeServices去实现父类AbstractRememberMeServices中的抽象方法。

在PersistentTokenBasedRememberMeServices中,有一个PersistentTokenRepository,会生成一个Token,并将这个Token写到cookie里面返回浏览器。PersistentTokenRepository的默认实现类是InMemoryTokenRepositoryImpl,该默认实现类会将token保存到内存中。这里我们配置了它的另一个实现类JdbcTokenRepositoryImpl,该类会将Token持久化到数据库中

// ... private PersistentTokenRepository tokenRepository = new InMemoryTokenRepositoryImpl(); protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) { String username = successfulAuthentication.getName(); logger.debug("Creating new persistent login for user " + username); // 创建一个PersistentRememberMeToken PersistentRememberMeToken persistentToken = new PersistentRememberMeToken( username, generateSeriesData(), generateTokenData(), new Date()); try { // 保存Token tokenRepository.createNewToken(persistentToken); // 将Token写到Cookie中 addCookie(persistentToken, request, response); } catch (Exception e) { logger.error("Failed to save persistent token ", e); } }

4、JdbcTokenRepositoryImpl将Token持久化到数据库

/** The default SQL used by createNewToken */ public static final String DEF_INSERT_TOKEN_SQL = "insert into persistent_logins (username, series, token, last_used) values(?,?,?,?)"; public void createNewToken(PersistentRememberMeToken token) { getJdbcTemplate().update(insertTokenSql, token.getUsername(), token.getSeries(), token.getTokenValue(), token.getDate()); }

查看数据库,可以看到往persistent_logins 中插入了一条数据:

5、重启服务,发送第二次认证请求,只会携带Cookie。

所以直接会被RememberMeAuthenticationFilter拦截,并且此时内存中没有认证信息。

可以看到,此时的RememberMeServices是由PersistentTokenBasedRememberMeServices实现

6、在PersistentTokenBasedRememberMeServices中,调用processAutoLoginCookie方法,获取用户相关信息

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) + "'"); } // 从Cookie中获取Series和Token final String presentedSeries = cookieTokens[0]; final String presentedToken = cookieTokens[1]; //在数据库中,通过Series查询PersistentRememberMeToken PersistentRememberMeToken token = tokenRepository .getTokenForSeries(presentedSeries); if (token == null) { throw new RememberMeAuthenticationException( "No persistent token found for series id: " + presentedSeries); } // 校验数据库中Token和Cookie中的Token是否相同 if (!presentedToken.equals(token.getTokenValue())) { tokenRepository.removeUserTokens(token.getUsername()); throw new CookieTheftException( messages.getMessage( "PersistentTokenBasedRememberMeServices.cookieStolen", "Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.")); } // 判断Token是否超时 if (token.getDate().getTime() + getTokenValiditySeconds() * 1000L < System .currentTimeMillis()) { throw new RememberMeAuthenticationException("Remember-me login has expired"); } if (logger.isDebugEnabled()) { logger.debug("Refreshing persistent login token for user '" + token.getUsername() + "', series '" + token.getSeries() + "'"); } // 创建一个新的PersistentRememberMeToken PersistentRememberMeToken newToken = new PersistentRememberMeToken( token.getUsername(), token.getSeries(), generateTokenData(), new Date()); try { //更新数据库中Token tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(), newToken.getDate()); //重新写到Cookie addCookie(newToken, request, response); } catch (Exception e) { logger.error("Failed to update token: ", e); throw new RememberMeAuthenticationException( "Autologin failed due to data access problem"); } //调用UserDetailsService获取用户信息 return getUserDetailsService().loadUserByUsername(token.getUsername()); }

7、获取用户相关信息后,再调用AuthenticationManager去认证授权

关于SpringSecurityRememberme使用及原理是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

数据 登录 数据库 认证 配置 信息 方法 用户 表单 原理 成功 内存 接口 问题 数据源 时间 更多 身份 身份认证 面的 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 疫情对互联网科技公司影响 港股互联网科技股 互联网科技公司发展 互联网金融科技创新 互联网女皇 腾讯科技 米客互联网科技 顺网科技2021年互联网排名 海南科技产业互联网平台 搜狐科技互联网 洛阳昕诺飞互联网科技有限公司 中国互联网十大科技股排名 翼展科技 首家互联网医院 沐思想互联网科技有限公司 互联网科技年终奖 陕西云淼互联网科技公司 广州梦谷互联网科技有限公司领导 互联网科技对化妆品行业 互联网科技大佬云集 互联网的黑科技实验室 互联网科技创业有什么好项目 互联网科技卖菜 互联网科技公司怎么样 西安互联网科技公司 科技与互联网的利与弊 恒银科技与互联网金融 崇明区互联网教育科技售后服务 有人说阿里系是互联网科技企业 米泉互联网科技专业怎么样 北京瑞云互联网科技有限公司 宁波允成互联网科技有限公司
0