知識庫 / Spring / Spring Security RSS 訂閱

Spring Security 新密碼存儲

Spring Security
HongKong
6
02:05 PM · Dec 06 ,2025

1. 簡介

隨着最新版 Spring Security 的發佈,許多方面都發生了變化。其中之一是如何在我們的應用程序中處理密碼編碼。

在本教程中,我們將探索這些變化。

稍後,我們將瞭解如何配置新的委託機制,以及如何更新我們現有的密碼編碼,而不會讓我們的用户察覺到變化。

2. Spring Security 5.x 中的相關變更

Spring Security 團隊宣佈將 PasswordEncoderorg.springframework.security.authentication.encoding 中標記為棄用。 這是一項合理的舉措,因為舊接口並未設計用於隨機生成的鹽。 因此,版本 5 移除了此接口。

此外,Spring Security 改變了它處理編碼密碼的方式。 在以前的版本中,每個應用程序僅使用一種密碼編碼算法。

默認情況下,StandardPasswordEncoder 處理了此任務。 它使用 SHA-256 進行編碼。 通過更改密碼編碼器,我們可以切換到另一種算法。 但是,我們的應用程序必須堅持使用一種算法。

版本 5.0 引入了密碼編碼委託的概念。 現在,我們可以為不同的密碼使用不同的編碼。 Spring 通過為編碼密碼添加的前綴來識別算法。

以下是 bcrypt 編碼密碼的示例:

{bcrypt}$2b$12$FaLabMRystU4MLAasNOKb.HUElBAabuQdX59RWHq5X.9Ghm692NEi

請注意,bcrypt 的指定方式在開頭使用花括號。

3. 委託配置

如果密碼哈希沒有前綴,委託過程將使用默認編碼器。因此,默認情況下,我們獲取 StandardPasswordEncoder

這使其與舊版 Spring Security 的默認配置兼容。

在 Spring Security 5 中,Spring Security 引入了 PasswordEncoderFactories.createDelegatingPasswordEncoder()。此工廠方法返回一個配置的 DelegationPasswordEncoder 實例。

對於沒有前綴的密碼,該實例確保上述默認行為。對於包含前綴的密碼哈希,委託將相應地進行。

Spring Security 團隊在最新版本的 相關 JavaDoc 中列出了支持的算法。

當然,Spring 允許我們配置此行為。

假設我們想要支持:

  • bcrypt 作為我們的新默認值
  • scrypt 作為替代方案
  • SHA-256 作為當前使用的算法。

此配置的設置將如下所示:

@Bean
public PasswordEncoder delegatingPasswordEncoder() {
    PasswordEncoder defaultEncoder = new StandardPasswordEncoder();
    Map<String, PasswordEncoder> encoders = new HashMap<>();
    encoders.put("bcrypt", new BCryptPasswordEncoder());
    encoders.put("scrypt", new SCryptPasswordEncoder(1, 1, 1, 1, 10));

    DelegatingPasswordEncoder passworEncoder = new DelegatingPasswordEncoder(
      "bcrypt", encoders);
    passworEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder);

    return passworEncoder;
}

4. 遷移密碼編碼算法

在上一節中,我們探討了如何根據我們的需求配置密碼編碼。 因此,現在我們將處理如何將已編碼的密碼切換到新的算法。

假設我們想要將編碼方式從 SHA-256 更改為 bcrypt,但我們不想讓用户更改他們的密碼。

一個可能的解決方案是使用登錄請求。 在此時,我們可以訪問平時的憑據。 這就是我們能夠獲取當前密碼並重新編碼它的時刻。

因此,我們可以使用 Spring 的 AuthenticationSuccessEvent 來完成此操作。 此事件在用户成功登錄我們的應用程序後觸發。

以下是示例代碼:

@Bean
public ApplicationListener<AuthenticationSuccessEvent>
  authenticationSuccessListener( PasswordEncoder encoder) {
    return (AuthenticationSuccessEvent event) -> {
        Authentication auth = event.getAuthentication();

        if (auth instanceof UsernamePasswordAuthenticationToken
          && auth.getCredentials() != null) {

            CharSequence clearTextPass = (CharSequence) auth.getCredentials();
            String newPasswordHash = encoder.encode(clearTextPass);

            // [...] Update user's password

            ((UsernamePasswordAuthenticationToken) auth).eraseCredentials();
        }
    };
}

在之前的片段中:

  • 我們從提供的身份驗證詳情中檢索了明文用户密碼。
  • 創建了一個新的密碼哈希,使用了新的算法。
  • 從身份驗證令牌中刪除了明文密碼。

默認情況下,由於 Spring Security 會盡快刪除明文密碼,因此無法提取密碼。

因此,我們需要配置 Spring,以便保留明文密碼版本。

此外,我們需要註冊我們的編碼委託。

@Configuration
public class PasswordStorageWebSecurityConfigurer {

    @Bean
    public AuthenticationManager authManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authenticationManagerBuilder = 
            http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.eraseCredentials(false)
            .userDetailsService(getUserDefaultDetailsService())
            .passwordEncoder(passwordEncoder());
        return authenticationManagerBuilder.build();
    }

   // ...
}

5. 結論

在本文中,我們介紹了 5.x 版本中可用的新密碼編碼功能。

我們還了解了如何配置多個密碼編碼算法來編碼密碼。此外,我們還探索了一種更改密碼編碼的方法,而無需破壞現有編碼。

最後,我們描述瞭如何使用 Spring 事件以透明的方式更新加密用户密碼,從而使我們能夠在不向用户披露的情況下無縫更改編碼策略。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.