1. 概述
本教程將演示如何使用 Spring Security 在 Web 應用程序中啓用和配置“記住我”功能。設置具有安全性和簡單表單登錄的 MVC 應用程序,此前已經討論過。
該機制將能夠 跨多個會話識別用户 – 因此,首先要理解的是“記住我”功能僅在會話超時後才會啓動。默認情況下,這發生在不活動 30 分鐘後,但可以通過 web.xml 配置超時時間。
注意:本教程側重於 基於標準 Cookie 的方法。對於持久化方法,請參閲 Spring Security – Persistent Remember Me 指南。
2. 安全配置
讓我們看看如何使用 Java 設置安全配置:
@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.authorizeHttpRequests(auth -> auth.requestMatchers("/anonymous*")
.anonymous()
.requestMatchers("/login*")
.permitAll()
.anyRequest()
.authenticated())
.formLogin(formLogin -> formLogin.loginPage("/login.html")
.loginProcessingUrl("/login")
.failureUrl("/login.html?error=true"))
.rememberMe(rememberMe -> rememberMe.key("uniqueAndSecret"))
.logout(logout -> logout.deleteCookies("JSESSIONID"));
return http.build();
}
正如你所看到的,使用 rememberMe() 方法進行的基本配置非常簡單,同時通過額外的選項保持了極大的靈活性。 在這裏,key 非常重要,它是整個應用程序的私有值,用於生成令牌的內容。
此外,可以使用 tokenValiditySeconds() 配置令牌的有效時間,從默認的 2 周更改為例如 1 天:
rememberMe(rememberMe -> 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. 登錄表單
登錄表單與我們用於表單登錄時使用的表單類似:
<html>
<head></head>
<body>
<h1>登錄</h1>
<form name='f' action="login" method='POST'>
<table>
<tr>
<td>用户名:</td>
<td><input type='text' name='username' value=''></td>
</tr>
<tr>
<td>密碼:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td>記住我:</td>
<td><input type="checkbox" name="remember-me" /></td>
</tr>
<tr>
<td><input name="submit" type="submit" value="提交" /></td>
</tr>
</table>
</form>
</body>
</html>
注意新增的複選框輸入 – 對應於remember-me。 此新增輸入足以啓用記住我功能。
此默認路徑也可以通過以下方式更改:
.rememberMe().rememberMeParameter("remember-me-new")
4. Cookie
該機制將創建一個額外的 Cookie – “記住我” Cookie – 當用户登錄時。記住我 Cookie 包含以下數據:
- username – 用於標識已登錄的 principalexpirationTime – 過期 Cookie;默認值為 2 周MD5 哈希值 – 前 2 個值(username 和 expirationTime)以及 password 和預定義的 key這裏首先需要注意的是,username 和 password 都包含在 Cookie 中 – 這意味着如果其中任何一個發生更改,Cookie 將不再有效。 此外,username 可以從 Cookie 中讀取。
- 使用“記住我”選項登錄
- 等待會話過期(或在瀏覽器中刪除 JSESSIONID 餅乾)
- 刷新頁面
此外,重要的是要理解,如果“記住我” Cookie 被捕獲,則該機制可能存在漏洞。 Cookie 將在過期或憑據更改時保持有效和可用。
5. 在實踐中
為了方便地觀察“記住我”機制的工作,您可以:
如果未啓用“記住我”,在餅乾過期後,用户應 被重定向回登錄頁面。 啓用“記住我”後,用户現在將 保持登錄狀態,藉助新的令牌/餅乾。
6. 結論
本教程介紹瞭如何在安全配置中設置和配置“記住我”功能,並簡要描述了cookie中存儲的數據。
當項目運行時,login.html可以在localhost上訪問。