1. 概述
本文將演示如何在 Spring Security 中設置 記住我功能 – 不僅使用標準 Cookie 方式,而是 採用更安全的解決方案,使用持久化。
作為快速介紹 – Spring 可以配置為在瀏覽器會話之間記住登錄憑據。這允許您登錄到網站,然後在訪問該網站時自動為您登錄(即使在您關閉瀏覽器期間)。
2. 兩種“記住我”解決方案
Spring 提供了兩種略有不同的實現方案來解決這個問題。它們都使用 UsernamePasswordAuthenticationFilter,通過鈎子來調用 RememberMeServices 實現。我們之前已經介紹了標準“記住我”解決方案,它僅使用一個 cookie,即 remember-me cookie,其中包含用户名、過期時間以及包含密碼的 MD5 哈希值。由於它包含密碼的哈希值,該解決方案在 cookie 被捕獲時可能存在漏洞
考慮到這一點,讓我們來查看第二種方法——使用 PersistentTokenBasedRememberMeServices 在會話之間將持久登錄信息存儲在數據庫表中。
3. 前提條件 – 創建數據庫表
首先,我們需要在數據庫中創建登錄信息 – 我們需要創建一個表來存儲數據:create table if not exists persistent_logins (
username varchar_ignorecase(100) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null
);
這是通過以下 XML 配置自動創建的,使用內存中的 H2 數據庫:
<!-- create H2 embedded database table on startup -->
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:/persisted_logins_create_table.sql"/>
</jdbc:embedded-database>為了完整性,以下是持久化設置的方式:
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence-h2.properties" })
public class DatabaseConfig {
@Autowired private Environment env;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
}4. The Spring Security Configuration
The first key configuration is the Remember-Me Http Configuration (notice the dataSource property):
<http use-expressions="true">
...
<remember-me data-source-ref="dataSource" token-validity-seconds="86400"/>
<http">
下一步,我們需要配置實際的 RememberMeService 和 JdbcTokenRepository(它也使用了 dataSource):
<!-- Persistent Remember Me Service -->
<beans:bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg value="myAppKey" />
<beans:constructor-arg ref="jdbcTokenRepository" />
<beans:constructor-arg ref="myUserDetailsService" />
</beans:bean>
<!-- Uses a database table to maintain a set of persistent login data -->
<beans:bean id="jdbcTokenRepository"
class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
<beans:property name="createTableOnStartup" value="false" />
<beans:property name="dataSource" ref="dataSource" />
</beans:bean>
<!-- Authentication Manager (uses same UserDetailsService as RememberMeService)-->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="myUserDetailsService"/>
</authentication-provider>
</authentication-manager>
5. Cookie
正如我們所提到的,標準 `TokenBasedRememberMeServices 在 Cookie 中存儲了哈希後的用户密碼。
該解決方案——<em >PersistentTokenBasedRememberMeServices</em > 使用一個唯一的系列標識符用於用户 身份。此標識符用於記錄用户的初始登錄,並在用户在持久會話期間自動登錄時保持不變。它還包含一個 `隨機令牌 ,該令牌在用户通過持久記住我功能登錄時會重新生成。
此係列和令牌的組合被持久保存,使得暴力破解攻擊的可能性極低。
6. 在實踐中
要觀察“記住我”機制在瀏覽器中的工作,您可以:
- 使用“記住我”功能登錄
- 關閉瀏覽器
- 重新打開瀏覽器並返回同一頁面。刷新。
- 您仍然會保持登錄狀態
未啓用“記住我”時,當 cookie 過期後,用户應被重定向回登錄頁面。 啓用“記住我”時,用户現在將通過新的 token/cookie 保持登錄狀態。
您還可以查看瀏覽器中的 cookie 以及存儲在數據庫中的持久化數據(請注意,您可能需要從嵌入式 H2 實現中切換以進行此操作)。
7. 結論
本教程演示瞭如何設置和配置持久化的“記住我”令牌功能。它也是對先前文章的補充,該文章討論了基於 Cookie 令牌的標準功能。數據庫方法更安全,因為密碼詳情不會存儲在 Cookie 中——但它也需要稍微更多的配置。