RememberMe基本用法

我们先来看一种最简单的用法。

首先创建一个 Spring Boot 工程,引入 Spring-boot-starter-security 依赖。工程创建成功后,添加一人 HelloController 并创建一人测试接口,代码如下:

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}

然后创建 SecurityConfig 配置文件:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("javaboy")
                .password("123")
                .roles("admin");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .rememberMe()
                .key("javaboy")
                .and()
                .csrf().disable();
    }
}

这里我们主要是调用了HttpSecurity 中的 rememberMe 方法并配置了一个 key(key 在这里很重要——它是整个应用程序的私有秘钥,将在生成令牌的内容时使用),该方法最终会向过滤器链中添加 RememberMeAuthenticationFilter 过滤器。

配置完成后,启动项目,当我们访问 /hello 接口时,会自动重定向到登录页面,如图6-2 所示。

image 2024 04 13 10 31 54 999
Figure 1. 图6-2 添加了RememberMe功能后的默认登录页面

可以看到,此时的默认登录页面多了一个 RememberMe 选项,勾选上 RememberMe,登录成功之后,我们就可以访问 /hello 接口了。访问完成后,关闭浏览器再重新打开,此时不需要登录就可以直接访问 /hello 接口;同时,如果关闭掉服务端重新打开,再去访问 /hello 接口,发现此时也不需要登录了。

那么这一切是怎么实现的呢?打开浏览器控制台,我们来分析整个登录过程。

首先,当我们单击登录按钮时,多了一个请求参数 remember-me,如图6-3所示。

image 2024 04 13 10 38 23 024
Figure 2. 图6-3 开启 RememberMe 功能后的请求参数

很明显,remember-me 参数就是用来告诉服务端是否开启 RememberMe 功能,如果开发者自定义登录页面,那么默认情况下,是否开启 RememberMe 的参数就是remember-me。

当请求成功后,在响应头中多出了一个 Set-Cookie,如图6-4所示。

image 2024 04 13 10 39 28 578
Figure 3. 图6-4 响应头中多出一个Set-Cookie字段

在响应头中给出了一个 remember-me 字符串。以后所有请求的请求头 Cookie 字段,都会自动携带上这个令牌,服务端利用该令牌可以校验用户身份是否合法。

大致的流程就是这样,但是大家发现这种方式安全隐患很大,一旦 remember-me 令牌泄漏,恶意用户就可以掌看这入令牌去随意访问系统资源。持久化令牌和二次校验可以在一定程度上降低该问题带来的风险。