Spring Security更換加密方式的完整方案
隨著現(xiàn)在對軟件系統(tǒng)安全性要求的越來越嚴(yán)苛,對于很多項目,升級密碼都是勢在必行的,若項目使用Spring Security框架,只需稍作修改,便可達到更換加密方式,且自動更新存量數(shù)據(jù)的密碼加密放肆。在Spring Security中更換密碼加密方式,通常涉及遷移舊有用戶密碼并配置新的加密策略。以下是完整步驟和示例代碼:
1. 理解Spring Security的加密接口
核心接口是PasswordEncoder,常用實現(xiàn)類:
BCryptPasswordEncoder(推薦)SCryptPasswordEncoderPbkdf2PasswordEncoderArgon2PasswordEncoderNoOpPasswordEncoder(明文,僅測試用)
2. 遷移方案(新舊密碼共存)
使用DelegatingPasswordEncoder。DelegatingPasswordEncoder 是 Spring Security 中用于密碼加密的核心組件,主要用于代理多種加密策略,兼容舊密碼格式并支持升級加密方式,支持多種加密格式自動適配:
先來看DelegatingPasswordEncoder的構(gòu)造方法:
public DelegatingPasswordEncoder(String idForEncode, Map<String, PasswordEncoder> idToPasswordEncoder) {
if (idForEncode == null) {
throw new IllegalArgumentException("idForEncode cannot be null");
} else if (!idToPasswordEncoder.containsKey(idForEncode)) {
throw new IllegalArgumentException("idForEncode " + idForEncode + "is not found in idToPasswordEncoder " + idToPasswordEncoder);
} else {
for(String id : idToPasswordEncoder.keySet()) {
if (id != null) {
if (id.contains("{")) {
throw new IllegalArgumentException("id " + id + " cannot contain " + "{");
}
if (id.contains("}")) {
throw new IllegalArgumentException("id " + id + " cannot contain " + "}");
}
}
}
this.idForEncode = idForEncode;
this.passwordEncoderForEncode = (PasswordEncoder)idToPasswordEncoder.get(idForEncode);
this.idToPasswordEncoder = new HashMap(idToPasswordEncoder);
}
}
其中參數(shù)idForEncode決定了密碼編碼器的類型,而idToPasswordEncoder決定了匹配密碼時的兼容的密碼編碼器的類型,且idToPasswordEncoder中必須包含idForEncode,否則新密碼加密后將無法匹配。
查看DelegatingPasswordEncoder類的類圖可知,DelegatingPasswordEncoder類是PasswordEncoder的實現(xiàn)類。

根據(jù)DelegatingPasswordEncoder的構(gòu)造器,定義PasswordEncoder密碼編碼器:
@Bean
public PasswordEncoder passwordEncoder() {
String idForEncode = "bcrypt"; // 默認(rèn)使用BCrypt
Map<String, PasswordEncoder> idToPasswordEncoder = new HashMap<>();
idToPasswordEncoder.put(idForEncode, new BCryptPasswordEncoder());
idToPasswordEncoder.put("sha256", new MessageDigestPasswordEncoder("SHA-256")); // 舊系統(tǒng)加密方式
return new DelegatingPasswordEncoder(idForEncode, idToPasswordEncoder);
}
3. 密碼存儲格式要求
認(rèn)證時根據(jù)前綴匹配加密器:
存儲格式示例:
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
{sha256}5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
4. 數(shù)據(jù)庫密碼遷移腳本
-- 將舊密碼加前綴
UPDATE t_user SET password = CONCAT('{sha256}', password)
WHERE password NOT LIKE '{_}%';
5. 安全配置示例
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username=?")
.authoritiesByUsernameQuery("SELECT username, authority FROM authorities WHERE username=?");
}
@Bean
public PasswordEncoder passwordEncoder() {
// 委托式編碼器配置
String idForEncode = "bcrypt"; // 默認(rèn)使用BCrypt
Map<String, PasswordEncoder> idToPasswordEncoder = new HashMap<>();
idToPasswordEncoder.put(idForEncode, new BCryptPasswordEncoder());
idToPasswordEncoder.put("sha256", new MessageDigestPasswordEncoder("SHA-256")); // 舊系統(tǒng)加密方式
return new DelegatingPasswordEncoder(idForEncode, idToPasswordEncoder);
}
}
6. 密碼自動升級策略(可選)
密碼自動升級策略,適用于用戶登錄時自動更新密碼格式,需要自定義PasswordEncoder的實現(xiàn)類,并在第5點安全配置中使用,可參照BCryptPasswordEncoder進行實現(xiàn)。
public class AutoUpgradePasswordEncoder implements PasswordEncoder {
private final PasswordEncoder currentEncoder;
private final PasswordEncoder newEncoder;
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (currentEncoder.matches(rawPassword, encodedPassword)) {
// 匹配成功且是舊編碼時,觸發(fā)密碼升級
if (encodedPassword.startsWith("{sha256}")) {
String newPass = newEncoder.encode(rawPassword);
// 調(diào)用DAO更新數(shù)據(jù)庫密碼...
}
return true;
}
return newEncoder.matches(rawPassword, encodedPassword);
}
// encode()方法需實現(xiàn)...
}
7. 注意事項
- 前綴不可省略:
{id}encodedPassword格式是識別關(guān)鍵 - 加密強度:
// 調(diào)整BCrypt強度 (默認(rèn)10) new BCryptPasswordEncoder(12)
- 禁用弱加密:避免使用MD5/SHA-1等已被破解的算法
- 密碼遷移:在系統(tǒng)低負(fù)載時段執(zhí)行數(shù)據(jù)庫更新
- 測試策略:保留舊密碼的用戶測試賬號
8. 最佳實踐
主推算法:BCrypt(自適應(yīng)強度抗GPU破解)
過渡方案:

安全規(guī)范:
- 密碼強度要求:至少10位(字母+數(shù)字+特殊字符)
- 定期輪換:每90天提示修改密碼(配合密碼歷史策略)
9.總結(jié)
Spring Security項目的密碼升級主要是通過配置PasswordEncoder進行實現(xiàn),但需要注意需要進行密碼的遷移(舊密碼添加前綴)。
- 密碼強度要求:至少10位(字母+數(shù)字+特殊字符) - 定期輪換:每90天提示修改密碼(配合密碼歷史策略)
通過上述設(shè)計,系統(tǒng)可以同時支持新舊用戶認(rèn)證,并逐步將舊密碼升級到更安全的加密方式,整個過程對用戶幾乎無感知。
以上就是Spring Security更換加密方式的完整方案的詳細(xì)內(nèi)容,更多關(guān)于Spring Security更換加密方式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring之兩種任務(wù)調(diào)度Scheduled和Async詳解
這篇文章主要介紹了Spring之兩種任務(wù)調(diào)度Scheduled和Async,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
將InputStream轉(zhuǎn)化為base64的實例
這篇文章主要介紹了將InputStream轉(zhuǎn)化為base64的實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
Java如何使用ReentrantLock實現(xiàn)長輪詢
這篇文章主要介紹了如何使用ReentrantLock實現(xiàn)長輪詢,對ReentrantLock感興趣的同學(xué),可以參考下2021-04-04
使用MyBatisPlus自動生成代碼后tomcat運行報錯的問題及解決方法
這篇文章主要介紹了使用MyBatisPlus自動生成代碼后tomcat運行報錯的問題及解決方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08

