Spring Security靈活的PasswordEncoder加密方式解析
導讀
本章基于Spring Security 5.4.1
版本編寫,從5.x
版本開始引入了很多新的特性。
為了適配老系統(tǒng)的安全框架升級,Spring Security
也是費勁了心思,支持不同的密碼加密方式,而且根據(jù)不同的用戶可以使用不同的加密方式。
構建Spring Security項目
Spring Security
的集成使用還是很簡單的,根據(jù)項目使用的框架不同大致分為兩種集成方式:
SpringBoot方式集成
SecurityBom方式集成
SpringBoot方式構建
在pom.xml
文件內(nèi)添加如下內(nèi)容:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
SecurityBom方式構建
spring-security-bom
是一個提供了Spring Security
指定版本的全部默認依賴的pom
類型項目,我們可以通過dependencyManagement
進行配置到項目中,這樣我們就可以直接添加對應的dependency
了(注意:版本號因為bom已經(jīng)注定,所以dependency不需要指定.)。
在pom.xml
文件內(nèi)添加如下內(nèi)容:
<dependencies> // ...省略其他依賴 <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <!--配置SecurityBom--> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-bom</artifactId> <version>5.4.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
注意事項:我們構建Web類型的安全項目時,spring-security-config
、spring-security-core
、spring-security-web
三個依賴都是必須添加的。
PasswordEncoder
PasswordEncoder
是Spring Security
提供的密碼加密方式的接口定義,源碼類如下所示:
public interface PasswordEncoder { /** * Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or * greater hash combined with an 8-byte or greater randomly generated salt. */ String encode(CharSequence rawPassword); /** * Verify the encoded password obtained from storage matches the submitted raw * password after it too is encoded. Returns true if the passwords match, false if * they do not. The stored password itself is never decoded. * * @param rawPassword the raw password to encode and match * @param encodedPassword the encoded password from storage to compare with * @return true if the raw password, after encoding, matches the encoded password from * storage */ boolean matches(CharSequence rawPassword, String encodedPassword); /** * Returns true if the encoded password should be encoded again for better security, * else false. The default implementation always returns false. * @param encodedPassword the encoded password to check * @return true if the encoded password should be encoded again for better security, * else false. */ default boolean upgradeEncoding(String encodedPassword) { return false; } }
#encode
該方法提供了明文密碼的加密處理,加密后密文的格式主要取決于
PasswordEncoder
接口實現(xiàn)類實例。#matches
匹配存儲的密碼以及登錄時傳遞的密碼(
登錄密碼是經(jīng)過加密處理后的字符串
)是否匹配,如果匹配該方法則會返回true
.
內(nèi)置的PasswordEncoder實現(xiàn)列表
NoOpPasswordEncoder(已廢除)
明文密碼加密方式,該方式已被廢除(不建議在生產(chǎn)環(huán)境使用),不過還是支持開發(fā)階段測試Spring Security
的時候使用。
DelegatingPasswordEncoder
在之前版本集成Spring Secuirty
時,我們需要通過@Bean
的方式來配置全局統(tǒng)一使用的密碼加密方式(PasswordEncoder
),當然這種方式現(xiàn)在還是適用的,不過在5.x
版本開始為了支持動態(tài)的多種密碼加密方式,DelegatingPasswordEncoder
委托加密方式類應用而生,它內(nèi)部其實是一個Map集合,根據(jù)傳遞的Key(Key為加密方式)獲取Map集合的Value,而Value則是具體的PasswordEncoder
實現(xiàn)類。
DelegatingPasswordEncoder
建立密碼格式的規(guī)則,格式如:{bcrypt}encodePassword
,示例如下所示:
// {bcrypt}格式會委托給BCryptPasswordEncoder加密類 {bcrypt}$2a$10$iMz8sMVMiOgRgXRuREF/f.ChT/rpu2ZtitfkT5CkDbZpZlFhLxO3y // {pbkdf2}格式會委托給Pbkdf2PasswordEncoder加密類 {pbkdf2}cc409867e39f011f6332bbb6634f58e98d07be7fceefb4cc27e62501594d6ed0b271a25fd9f7fc2e // {MD5}格式會委托給MessageDigestPasswordEncoder加密類 {MD5}e10adc3949ba59abbe56e057f20f883e // {noop}明文方式,委托給NoOpPasswordEncoder {noop}123456 // ...
指定用戶使用PasswordEncoder
DelegatingPasswordEncoder
是默認的PasswordEncoder
加密方式,所以我們可以為不同的用戶配置所使用不同的密碼加密方式,只需要密碼格式按照:{away}encodePassword
來進行持久化即可。
@Configuration @EnableWebSecurity public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .formLogin() .and() .csrf() .disable() .authorizeRequests() .antMatchers("/**") .authenticated(); } @Bean public UserDetailsService users() { // {MD5}value必須大寫,value值必須是32位小寫 // admin UserDetails admin = User.builder() //.passwordEncoder(encoder::encode) .username("admin").password( "{MD5}e10adc3949ba59abbe56e057f20f883e" ).roles("admin").build(); // hengboy UserDetails hengboy = User.builder() .username("hengboy") .password("{bcrypt}$2a$10$iMz8sMVMiOgRgXRuREF/f.ChT/rpu2ZtitfkT5CkDbZpZlFhLxO3y") .roles("admin") .build(); // yuqiyu UserDetails yuqiyu = User.builder().username("yuqiyu") //.password("{noop}123456") .password("{pbkdf2}cc409867e39f011f6332bbb6634f58e98d07be7fceefb4cc27e62501594d6ed0b271a25fd9f7fc2e") .roles("user").build(); return new InMemoryUserDetailsManager(admin, yuqiyu, hengboy); } }
上面是使用內(nèi)存方式存儲安全用戶的實現(xiàn)代碼,在創(chuàng)建UserDetailsService
類的實例時將用戶列表通過構造參數(shù)進行傳遞。
所創(chuàng)建的用戶:admin
,采用MD5
的加密方式進行密碼編碼,這里需要注意的是MD5加密后的字符串必須為小寫32位。
所創(chuàng)建的用戶:hengboy
,采用bcrypt
方式進行密碼編碼。
所創(chuàng)建的用戶:yuqiyu
,采用pbkdf2
方式進行密碼編碼。
覆蓋默認的PasswordEncoder
Spring Security 5.x
版本默認的PasswordEncoder
方式改成了DelegatingPasswordEncoder
委托類,不過如果是通過PasswordEncoderFactories#createDelegatingPasswordEncoder
方法創(chuàng)建的DelegatingPasswordEncoder
實例時,默認其實使用的還是BCryptPasswordEncoder
,源碼如下所示:
public static PasswordEncoder createDelegatingPasswordEncoder() { String encodingId = "bcrypt"; Map<String, PasswordEncoder> encoders = new HashMap<>(); encoders.put(encodingId, new BCryptPasswordEncoder()); // 省略... return new DelegatingPasswordEncoder(encodingId, encoders); }
如果我們項目中不需要使用DelegatingPasswordEncoder
委托密碼編碼方式,可以通過@Bean
的方式來統(tǒng)一配置全局共用的PasswordEncoder
,如下所示:
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
可以根據(jù)項目自行選擇所使用的PasswordEncoder
實現(xiàn)類。
以上就是Spring Security靈活的PasswordEncoder加密方式解析的詳細內(nèi)容,更多關于Spring Security PasswordEncoder加密的資料請關注腳本之家其它相關文章!
相關文章
mybatis?實現(xiàn)多層級collection嵌套
這篇文章主要介紹了mybatis?實現(xiàn)多層級collection嵌套,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03解決lambda表達式內(nèi)出現(xiàn)異常無法throw拋出的問題
這篇文章主要介紹了lambda表達式內(nèi)出現(xiàn)異常無法throw拋出的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09Java多線程教程之如何利用Future實現(xiàn)攜帶結果的任務
Callable與Future兩功能是Java?5版本中加入的,這篇文章主要給大家介紹了關于Java多線程教程之如何利用Future實現(xiàn)攜帶結果任務的相關資料,需要的朋友可以參考下2021-12-12關于SpringBoot+Mybatis報MapperScan.factoryBean()問題
解決SpringBoot+Mybatis中的MapperScan.factoryBean()問題,讓你的項目運行更順暢!本指南將帶你一步步解決這個問題,讓你的開發(fā)過程更加高效,不要錯過這個實用指南,快來一探究竟吧!2024-02-02elasticsearch 8.2.3 安裝及springboot簡單使用
這篇文章主要介紹了elasticsearch 8.2.3 安裝及springboot簡單使用,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06CommonMark 使用教程:將 Markdown 語法轉(zhuǎn)成 Html
這篇文章主要介紹了CommonMark 使用教程:將 Markdown 語法轉(zhuǎn)成 Html,這個技巧我們做任何網(wǎng)站都可以用到,而且非常好用。,需要的朋友可以參考下2019-06-06SpringBoot中使用?ThreadLocal?進行多線程上下文管理及注意事項小結
本文詳細介紹了ThreadLocal的原理、使用場景和示例代碼,并在SpringBoot中使用ThreadLocal保存請求中攜帶的用戶信息,ThreadLocal通過為每個線程維護獨立的變量副本,解決了線程安全問題,感興趣的朋友一起看看吧2025-02-02