在开启 RememberMe 时,Spring Security 做了什么?

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 【1月更文挑战第21天】上一篇介绍了,Spring Security 的 RememberMe 功能的实现原理.这一篇,我们来试着分析一下,在这个方法中,Spring Security 做了哪些事情。

上一篇《Spring Security 是如何“记住我”的? 》介绍了,Spring Security 的 RememberMe 功能的实现原理,我们可以在 Spring Security 的配置类中,对 HttpSecurity 对象调用一个 rememberMe() 方法,就可以开启这个功能。这一篇,我们来试着分析一下,在这个方法中,Spring Security 做了哪些事情。

如果你没读过前面那篇,可以先去读一下。

先从 rememberMe() 方法入手

查看 rememberMe() 方法的源码:

public RememberMeConfigurer<HttpSecurity> rememberMe() throws Exception {
   
    return getOrApply(new RememberMeConfigurer<>());
}

很简洁,就一句,配置了一个 RememberMeConfigurer,然后,我们重点看这个类。

RememberMeConfigurer

这个配置类里面有两个方法值得注意,一个是 init 方法,另一个是 configure 方法。我们一一来看。

init 方法

先看 init 方法的源码。

@Override
public void init(H http) throws Exception {
   
   validateInput();
   String key = getKey();
   RememberMeServices rememberMeServices = getRememberMeServices(http, key);
   http.setSharedObject(RememberMeServices.class, rememberMeServices);
   LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
   if (logoutConfigurer != null && this.logoutHandler != null) {
   
      logoutConfigurer.addLogoutHandler(this.logoutHandler);
   }
   RememberMeAuthenticationProvider authenticationProvider = new RememberMeAuthenticationProvider(key);
   authenticationProvider = postProcess(authenticationProvider);
   http.authenticationProvider(authenticationProvider);
   initDefaultLoginFilter(http);
}

这个方法里一共干了 3 件事儿,我们一个一个看。

配置 RememberMeServices

RememberMeServices 是通过这样代码创建的:

RememberMeServices rememberMeServices = getRememberMeServices(http, key);

我们找到 getRememberMeServices 的源码查看:

private RememberMeServices getRememberMeServices(H http, String key) throws Exception {
   
   if (this.rememberMeServices != null) {
   
      if (this.rememberMeServices instanceof LogoutHandler && this.logoutHandler == null) {
   
         this.logoutHandler = (LogoutHandler) this.rememberMeServices;
      }
      return this.rememberMeServices;
   }
   AbstractRememberMeServices tokenRememberMeServices = createRememberMeServices(http, key);
   tokenRememberMeServices.setParameter(this.rememberMeParameter);
   tokenRememberMeServices.setCookieName(this.rememberMeCookieName);
   if (this.rememberMeCookieDomain != null) {
   
        tokenRememberMeServices.setCookieDomain(this.rememberMeCookieDomain);
   }
   if (this.tokenValiditySeconds != null) {
   
      tokenRememberMeServices.setTokenValiditySeconds(this.tokenValiditySeconds);
   }
   if (this.useSecureCookie != null) {
   
      tokenRememberMeServices.setUseSecureCookie(this.useSecureCookie);
   }
   if (this.alwaysRemember != null) {
   
      tokenRememberMeServices.setAlwaysRemember(this.alwaysRemember);
   }
   tokenRememberMeServices.afterPropertiesSet();
   this.logoutHandler = tokenRememberMeServices;
   this.rememberMeServices = tokenRememberMeServices;
   return tokenRememberMeServices;
}

我们从上到下解析:

  • 如果已经配置了 rememberMeServices,则返回,否则继续向下执行。在返回之前,还会判断它是否是 LogoutHandler 的实现类,如果是的话,将其父只给 logoutHandler 属性。
  • 通过 createRememberMeServices 方法,创建一个 AbstractRememberMeServices 对象,并且配置一些属性,并将其赋值给当前配置类的 logoutHandlerrememberMeServices 属性,最后返回。

这里有一点有必要交代,之所以要将创建的 tokenRememberMeServices 赋值给 logoutHandler,是因为 AbstractRememberMeServices 类也实现了 LogoutHandler 接口,这个接口只有一个 logout 方法,实现这个方法后,就可以在用户注销登录之后,删除 RememberMeToken 及相关的信息。

这里我们还需要关注一下 createRememberMeServices 方法,是如何创建 AbstractRememberMeServices 对象的。这个方法的源码如下:

private AbstractRememberMeServices createRememberMeServices(H http, String key) {
   
   return (this.tokenRepository != null) ? createPersistentRememberMeServices(http, key)
         : createTokenBasedRememberMeServices(http, key);
}

上一篇文章(链接在本文开头)中,我曾经说过:

默认情况下 Spring Security 会使用 TokenBasedRememberMeServices ,提供了基础的功能。如果我们在开启 RememberMe 功能的时候,同时配置了一个 PersistentTokenRepository,那么 Spring Security 会自动选择 PersistentTokenBasedRememberMeServices 的实现。

这个判断逻辑就是在这里完成的。

至此,init 方法中,配置 RememberMeServices 的逻辑,我们就分析到这里。

配置 logoutHandler

接下来,会配置 logoutHandler,我们刚才通过源码分析过,在配置 RememberMeServices 的过程中,已经又了 logoutHandler 属性的值,这里只需要将其配置好,它的作用就是在用户注销登录后,删除 RememberMeToken 及相关的信息。

这一逻辑也可以从 AbstractRememberMeServices 的 logout 方法的源码中看出来:

@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
   this.logger.debug(LogMessage
         .of(() -> "Logout of user " + ((authentication != null) ? authentication.getName() : "Unknown")));
   cancelCookie(request, response);
}

配置 RememberMeAuthenticationProvider

上一篇文章(链接在本文开头)中我们也说到过,在RememberMeAuthenticationFilter 中,需要调用 authenticationManager.authenticate 方法进行身份认证。如果你了解 Spring Security 的认证流程的话就会知道,每一种认证方式都需要有一个对应的 Provider 来完成具体的认证工作。RememberMeAuthenticationProvider 就是来完成 RememberMe 认证的那个 Provider。

想要了解 Spring Security 的认证流程源码分析,可以参考我的这篇文章:Spring Security 认证流程

以上,就是 init 方法完成的工作。接下来看 configure 方法。

configure 方法

看源码:

@Override
public void configure(H http) {
   RememberMeAuthenticationFilter rememberMeFilter = new RememberMeAuthenticationFilter(
         http.getSharedObject(AuthenticationManager.class), this.rememberMeServices);
   if (this.authenticationSuccessHandler != null) {
      rememberMeFilter.setAuthenticationSuccessHandler(this.authenticationSuccessHandler);
   }
   rememberMeFilter = postProcess(rememberMeFilter);
   http.addFilter(rememberMeFilter);
}

这里比较简单,就是通过 AuthenticationManager 和刚才创建的 rememberMeServices 创建了一个 RememberMeAuthenticationFilter 过滤器,并将其加入过滤器链。RememberMe 相关的认证逻辑,正是在这个过滤器中调用的。

目录
相关文章
|
4天前
|
安全 Java 数据安全/隐私保护
|
8天前
|
安全 Java API
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(上)
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)
28 0
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(上)
|
1月前
|
存储 安全 Java
Spring Boot整合Spring Security--学习笔记
Spring Boot整合Spring Security--学习笔记
55 1
|
19天前
|
安全 数据安全/隐私保护
Springboot+Spring security +jwt认证+动态授权
Springboot+Spring security +jwt认证+动态授权
|
8天前
|
存储 安全 Java
第10章 Spring Security 的未来趋势与高级话题(2024 最新版)(下)
第10章 Spring Security 的未来趋势与高级话题(2024 最新版)
18 2
|
8天前
|
安全 Cloud Native Java
第10章 Spring Security 的未来趋势与高级话题(2024 最新版)(上)
第10章 Spring Security 的未来趋势与高级话题(2024 最新版)
23 2
|
8天前
|
安全 Java API
第5章 Spring Security 的高级认证技术(2024 最新版)(上)
第5章 Spring Security 的高级认证技术(2024 最新版)
34 0
|
8天前
|
存储 安全 Java
第3章 Spring Security 的用户认证机制(2024 最新版)(下)
第3章 Spring Security 的用户认证机制(2024 最新版)
32 0
|
8天前
|
存储 安全 Java
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(下)
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(下)
16 0
|
8天前
|
安全 Java 数据库
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(上)
第2章 Spring Security 的环境设置与基础配置(2024 最新版)
33 0