1. 概述
本文展示如何使用Spring Security配置启用和配置“记住我”(Remember Me)功能 。在前文中我们已经讨论过如何 搭建带有Security以及表单登录的MVC应用 。
该机制能跨session识别用户身份 ——所以首先要了解的是,"记住我"仅在session超时后才会介入。默认情况下,30分钟不活动会被认定为超时,但超时时间可以在web.xml中配置
注意:本教程重点介绍基于cookie的标准方法。 对于持久性化方法(即将token保存到数据库中),请查看 Spring Security –持久化“记住我”。
2. Security 配置
基于Java的Security配置:
@Configuration
@EnableWebSecurity
public class SecSecurityConfig {
@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.build();
}
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.withUsername("user1")
.password("{noop}user1Pass")
.authorities("ROLE_USER")
.build();
UserDetails admin = User.withUsername("admin1")
.password("{noop}admin1Pass")
.authorities("ROLE_ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/anonymous*")
.anonymous()
.antMatchers("/login*")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.failureUrl("/login.html?error=true")
.and()
.logout()
.deleteCookies("JSESSIONID")
.and()
.rememberMe()
.key("uniqueAndSecret");
return http.build();
}
}
如你所见, 使用rememberMe()方法的基本配置非常简单 ,同时通过其他选项可以保持非常高的灵活性。这里key非常重要 – 它是整个应用程序的私有密钥,在生成token时将使用。
此外, 使用tokenValiditySeconds()
可以配置token有效时间。比如由默认的二周,我们改为一天:
rememberMe().key("uniqueAndSecret").tokenValiditySeconds(86400)
我们还可以看一下等效的XML配置:
<http use-expressions="true">
<intercept-url pattern="/anonymous*" access="isAnonymous()" />
<intercept-url pattern="/login*" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login login-page='/login.html'
authentication-failure-url="/login.html?error=true" />
<logout delete-cookies="JSESSIONID" />
<remember-me key="uniqueAndSecret"/>
</http>
<authentication-manager id="authenticationManager">
<authentication-provider>
<user-service>
<user name="user1" password="{noop}user1Pass" authorities="ROLE_USER" />
<user name="admin1" password="{noop}admin1Pass" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
3. 登录表单
类似于前文Spring Security表单登录:
<html>
<head></head>
<body>
<h1>Login</h1>
<form name='f' action="login" method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td>Remember Me:</td>
<td><input type="checkbox" name="remember-me" /></td>
</tr>
<tr>
<td><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
</form>
</body>
</html>
只不过我们新增了一个”记住我“的复选框(checkbox )
默认字段名也可以被修改如下:
.rememberMe().rememberMeParameter("remember-me-new")
4. Cookie
当用户登录时,该机制会创建一个额外的cookie –“remember-me” cookie。
Remember Me cookie 包含下面的数据:
- username – 识别用户
- expirationTime – cookie过期时间; 默认为2周
- MD5 hash 对前2个值
username
、expirationTime
以及password
和预定义的key
进行MD5得到的hash值
这里首先要注意的是,用户名和密码都是 Cookie 的一部分 - 这意味着,如果其中任何一个更改,Cookie 将不再有效。此外,用户名也可以从cookie中读取。
此外,需要重点提醒的是,cookie将一直有效并可用,直到过期或更改凭据为止。所以如果"remember-me" cookie被窃取,则该机制可能会受到攻击。
5. 实践
为了验证”记住我“,你可以:
- 登录并勾选”记住我“
- 等待session过期 (或者浏览器中删除JSESSIONID cookie)
- 刷新页面
没有勾选"记住我",在cookie过期后,用户应该重定向回登录页面。 勾选后,用户能继续保持登录状态。
6. 总结
本教程介绍了如何在Security中配置“记住我”功能,并简要介绍了cookie中包含哪些类型的数据。
完整源代码可从Github上获取。
项目启动后, 访问登录页面http://localhost:8080/spring-security-mvc-custom/login.html。