最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Security如何實(shí)現(xiàn)升級(jí)密碼加密方式詳解

 更新時(shí)間:2023年01月04日 11:45:48   作者:bangiao  
這篇文章主要為大家介紹了Spring?Security實(shí)現(xiàn)升級(jí)密碼加密方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

本章內(nèi)容

  • 密碼加密方式怎么升級(jí)?
  • spring security底層怎么實(shí)現(xiàn)的密碼加密方式升級(jí)?

密碼加密方式怎么升級(jí)?

前面我們學(xué)過(guò)DelegatingPasswordEncoder類(lèi),但是不清楚他到底是做什么的,我也沒(méi)講的很清楚。所以呢,我們就重新再講一講它的另一個(gè)實(shí)際應(yīng)用。

小明呢,有一天在刷新聞。突然收到了一篇關(guān)于MD5加密存在重大漏洞的報(bào)告, 而最佳的代替加密方案是BCrypt。此時(shí)小明慌了。

因?yàn)樗?xiàng)目里面就是用著MD5加密。那現(xiàn)在怎么辦呢?小明的用戶(hù)體量比較大,你不可能叫客戶(hù)/程序員一個(gè)個(gè)去改是吧?

spring security就提供了一種這種情況的解決方案。

在用戶(hù)登錄你的賬戶(hù)時(shí),自動(dòng)的升級(jí)您的密碼加密方式。比如說(shuō)從MD5加密方式變成BCrypt

但是呢,這種方式有一個(gè)前提。您數(shù)據(jù)庫(kù)的用戶(hù)密碼必須要有ID,也就是花括號(hào)的那一部分{noop}123456。

當(dāng)然如果花括號(hào)沒(méi)有,然后數(shù)據(jù)體量就比較大,你只能重寫(xiě)DelegatingPasswordEncoder。

抄代碼的地方就在PasswordEncoderFactories#createDelegatingPasswordEncoder, 也就是你數(shù)據(jù)庫(kù)中的密碼沒(méi)有花括號(hào)部分(拿不到ID)的情況下, 使用BCryptPasswordEncoder

小白: "那在spring security中哪一部分定義了這項(xiàng)功能?"

升級(jí)方案源碼

首先我們得思考。什么情況下才會(huì)進(jìn)行密碼升級(jí)?

按照常理來(lái)說(shuō),應(yīng)該是在用戶(hù)登錄成功之后進(jìn)行密碼升級(jí)。所以我們?cè)谡以创a的時(shí)候,應(yīng)該先去找認(rèn)證成功的那部分源碼,絕對(duì)能找到這部分功能。

我第一反應(yīng)找UsernamePasswordAuthenticationFilterAbstractAuthenticationProcessingFilter抽象類(lèi)的doFilter方法

但是不幸的是這里找不到我們想要的功能。所以我立即反應(yīng)起來(lái)這項(xiàng)功能應(yīng)該是在認(rèn)證器這邊。

DaoAuthenticationProviderAbstractUserDetailsAuthenticationProvider

找到的認(rèn)證成功之后,他執(zhí)行的一段函數(shù)??梢悦黠@的看出有更新密碼的過(guò)程。

這里只要保證upgradeEncoding == true,那么就可以進(jìn)入更新密碼的過(guò)程。

這里我們看到了一段代碼this.userDetailsPasswordService, 可以百分百確定,我們的功能就在這個(gè)接口里面。

至于if的另一個(gè)函數(shù)upgradeEncoding, 你只要知道用戶(hù)輸入密碼和數(shù)據(jù)庫(kù)密碼ID不同就為 true, 相同就為 false, 當(dāng)然還有ID相同不同長(zhǎng)度的解決方案, 這里就不細(xì)談了

public interface UserDetailsPasswordService {
   UserDetails updatePassword(UserDetails user, String newPassword);
}

如果你英文能力比較強(qiáng)的話(huà),可以直接去查看這個(gè)接口上面就會(huì)有注釋?zhuān)瑑?nèi)容就是修改用戶(hù)名的密碼就這么簡(jiǎn)單。

既然已經(jīng)知道這個(gè)接口的存在了,那現(xiàn)在的問(wèn)題是怎么讓spring security調(diào)用我們所實(shí)現(xiàn)的這個(gè)接口呢?

我現(xiàn)在羅列出三張圖片。就可以從這三張圖片中總結(jié)出三種加載我們實(shí)現(xiàn)類(lèi)的方法。

實(shí)戰(zhàn)

第一種方式: Spring Bean

public class UserService1 implements UserDetailsService {
	@Resource
	private UsersMapper usersMapper;
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		Optional<Users> optionalUsers = Optional.ofNullable(usersMapper.loadUserByUsername(username));
		return optionalUsers.orElseThrow(() -> new UsernameNotFoundException("找不到用戶(hù)名"));
	}
}
@Bean
public UserService1 userService1() throws Exception {
    return new UserService1();
}

這種方式對(duì)應(yīng)著上面第3張圖。

那現(xiàn)在就會(huì)有人問(wèn)的。我并沒(méi)有寫(xiě)出從MD5加密方式升級(jí)到BCrypt加密方式。他是怎么自動(dòng)升級(jí)到BCrypt加密方式的?

帶著問(wèn)題看源碼

他是怎么自動(dòng)升級(jí)到BCrypt加密方式的?

我們知道spring security里面默認(rèn)使用的PasswordEncoder是這樣的。

@Bean
public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

不知道當(dāng)做知道哈

他們內(nèi)部的源碼是這樣的。

public static PasswordEncoder createDelegatingPasswordEncoder() {
    // 省略了一堆代碼
   String encodingId = "bcrypt";
   Map<String, PasswordEncoder> encoders = new HashMap<>();
   encoders.put(encodingId, new BCryptPasswordEncoder());
   encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
   encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
   return new DelegatingPasswordEncoder(encodingId, encoders);
}

嗯,你要注意這幾行代碼。

String encodingId = "bcrypt";
encoders.put(encodingId, new BCryptPasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);

別的什么都不看,只看encodingId變量。我們現(xiàn)在進(jìn)入DelegatingPasswordEncoder的內(nèi)部看看他的構(gòu)造函數(shù)。

public DelegatingPasswordEncoder(String idForEncode, Map<String, PasswordEncoder> idToPasswordEncoder,
      String idPrefix, String idSuffix) {
    // 省略一堆代碼
   this.idForEncode = idForEncode;
   this.passwordEncoderForEncode = idToPasswordEncoder.get(idForEncode);
   this.idToPasswordEncoder = new HashMap<>(idToPasswordEncoder);
   this.idPrefix = idPrefix;
   this.idSuffix = idSuffix;
}

encodingId在這個(gè)類(lèi)中被叫做idForEncode

了解了這個(gè)之后,再關(guān)注這幾行代碼。

this.idForEncode = idForEncode;
this.passwordEncoderForEncode = idToPasswordEncoder.get(idForEncode);

是不是相當(dāng)于

this.idForEncode = "bcrypt";
this.passwordEncoderForEncode = new BCryptPasswordEncoder();

我們?cè)倩氐竭@里看紅框框的這行代碼。

@Override
public String encode(CharSequence rawPassword) {
   return this.idPrefix + this.idForEncode + this.idSuffix + this.passwordEncoderForEncode.encode(rawPassword);
}

現(xiàn)在你對(duì)比一下這個(gè)函數(shù)跟前面構(gòu)造函數(shù)的名字看看。

構(gòu)造函數(shù)的變量叫 idForEncode , encode函數(shù)也叫 idForEncode , 前面的構(gòu)造函數(shù),我們發(fā)現(xiàn)這個(gè)變量其實(shí)已經(jīng)被保存在DelegatingPasswordEncoder類(lèi)里面了。而且值還是"bcrypt"

而構(gòu)造函數(shù)里面this.passwordEncoderForEncode = idToPasswordEncoder.get(idForEncode)

idToPasswordEncoder就是個(gè)Map, k是每種加密對(duì)象的id, v是每種加密算法

比如: key = "bcrypt", 那么 value = "BCryptPasswordEncoder"

所以 idToPasswordEncoderencode 函數(shù)時(shí), 是BCryptPasswordEncoder類(lèi)

小白: "什么玩意兒, 亂七八糟的, 看不懂"

小黑: "抱歉表達(dá)能力不行, 我簡(jiǎn)單點(diǎn)說(shuō)"

小黑: "因?yàn)?code>PasswordEncoderFactories.createDelegatingPasswordEncoder()函數(shù)使用bcrypt作為默認(rèn)加密方式, 所以在調(diào)用PasswordEncoder.encode時(shí)默認(rèn)也使用bcrypt"

小黑: "還不懂就配合下面的圖片看看"

造成它默認(rèn)是BCryptPasswordEncoder的原因是什么?

就上面這一行代碼

搞懂這個(gè)有什么作用呢?

Spring security默認(rèn)全部加密方式升級(jí)方案全部都是bcrypt,那如果我們要自定義升級(jí)到我們需要的加密方式呢?

重寫(xiě)PasswordEncoderFactories類(lèi), 把上面的變量修改成你需要修改的加密類(lèi)型, 并且往Map中添加加密類(lèi)型的對(duì)象

public static PasswordEncoder createDelegatingPasswordEncoder() {
   String encodingId = "無(wú)敵加密";
   Map<String, PasswordEncoder> encoders = new HashMap<>();
   encoders.put(encodingId, new 無(wú)敵加密PasswordEncoder());
    // 省略一堆代碼
   return new DelegatingPasswordEncoder(encodingId, encoders);
}

我去跑題了, 回歸正題

第二種方式: 多繼承接口方式

public class UserService implements UserDetailsService, UserDetailsPasswordService {
   @Resource
   private UsersMapper usersMapper;
   /**
    * 升級(jí)用戶(hù)密碼為當(dāng)前加密方式
    *
    * @param user        要修改的用戶(hù), 這個(gè)用戶(hù)必須有 id
    * @param newPassword 新的密碼, 該密碼已經(jīng)被 passwordEncoder 加密
    * @return
    */
   @Override
   public UserDetails updatePassword(UserDetails user, String newPassword) {
      if (user instanceof Users users) {
         users.setPassword(newPassword);
         usersMapper.updateByPrimaryKeySelective(users);
      }
      return user;
   }
   @Override
   public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      Optional<Users> optionalUsers = Optional.ofNullable(usersMapper.loadUserByUsername(username));
      return optionalUsers.orElseThrow(() -> new UsernameNotFoundException("找不到用戶(hù)"));
   }
}

這種方式對(duì)應(yīng)著上面三張圖片的第1張圖片給出的方案

第三種方式: HttpSecurity直接添加

@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
   AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
   authenticationManagerBuilder.authenticationProvider(/* 你的認(rèn)證七 */)
         .userDetailsService(/* 加載用戶(hù)方式 */)
         .passwordEncoder(/* 密碼加密方式 */)
         .userDetailsPasswordManager(/* 第三種更新加密的方式 */);
   return authenticationManagerBuilder.build();
}

這種方式比較麻煩, 只有你需要重寫(xiě)某個(gè)Provider的時(shí)候才會(huì)用到

一般我們使用第二種方式就行

以上就是Spring Security如何實(shí)現(xiàn)升級(jí)密碼加密方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring Security升級(jí)密碼加密的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java去除數(shù)組重復(fù)元素的四種方法

    java去除數(shù)組重復(fù)元素的四種方法

    本文給大家分享四種java去除數(shù)組重復(fù)元素的方法,每種方法通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-11-11
  • 深度解析Java中ArrayList的使用

    深度解析Java中ArrayList的使用

    ArrayList?類(lèi)是一個(gè)可以動(dòng)態(tài)修改的數(shù)組,與普通數(shù)組的區(qū)別就是它是沒(méi)有固定大小的限制,我們可以添加或刪除元素。本文將通過(guò)示例帶你深度解析Java中ArrayList的使用,需要的可以參考一下
    2022-09-09
  • 解決SpringMvc后臺(tái)接收json數(shù)據(jù)中文亂碼問(wèn)題的幾種方法

    解決SpringMvc后臺(tái)接收json數(shù)據(jù)中文亂碼問(wèn)題的幾種方法

    本篇文章主要介紹了解決SpringMvc后臺(tái)接收json數(shù)據(jù)中文亂碼問(wèn)題的幾種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java字符串轉(zhuǎn)駝峰格式的方法

    Java字符串轉(zhuǎn)駝峰格式的方法

    在開(kāi)發(fā)場(chǎng)景中,我們會(huì)遇到一些涉及字符串的轉(zhuǎn)化,本文主要介紹了Java字符串轉(zhuǎn)駝峰格式的方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Windows10安裝IDEA 2020.1.2的方法步驟

    Windows10安裝IDEA 2020.1.2的方法步驟

    這篇文章主要介紹了Windows10安裝IDEA 2020.1.2的方法步驟,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 淺談JDK8中的Duration Period和ChronoUnit

    淺談JDK8中的Duration Period和ChronoUnit

    在JDK8中,引入了三個(gè)非常有用的時(shí)間相關(guān)的API:Duration,Period和ChronoUnit。他們都是用來(lái)對(duì)時(shí)間進(jìn)行統(tǒng)計(jì)的,本文將會(huì)詳細(xì)講解一下這三個(gè)API的使用
    2021-06-06
  • Java超詳細(xì)整理講解各種排序

    Java超詳細(xì)整理講解各種排序

    這篇文章主要介紹了Java常用的排序算法及代碼實(shí)現(xiàn),在Java開(kāi)發(fā)中,對(duì)排序的應(yīng)用需要熟練的掌握,這樣才能夠確保Java學(xué)習(xí)時(shí)候能夠有扎實(shí)的基礎(chǔ)能力。那Java有哪些排序算法呢?本文小編就來(lái)詳細(xì)說(shuō)說(shuō)Java常見(jiàn)的排序算法,需要的朋友可以參考一下
    2022-07-07
  • WebSocket無(wú)法注入屬性的問(wèn)題及解決方案

    WebSocket無(wú)法注入屬性的問(wèn)題及解決方案

    這篇文章主要介紹了WebSocket無(wú)法注入屬性的問(wèn)題及解決方法,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • 如何解決LocalDateTime傳值JSON格式化問(wèn)題

    如何解決LocalDateTime傳值JSON格式化問(wèn)題

    這篇文章主要介紹了如何解決LocalDateTime傳值JSON格式化問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Spring AOP注解實(shí)戰(zhàn)指南

    Spring AOP注解實(shí)戰(zhàn)指南

    在現(xiàn)代軟件開(kāi)發(fā)中,面向切面編程(AOP)是一種強(qiáng)大的編程范式,本文將介紹如何在Spring框架中通過(guò)AspectJ注解以及對(duì)應(yīng)的XML配置來(lái)實(shí)現(xiàn)AOP,在不改變主業(yè)務(wù)邏輯的情況下增強(qiáng)應(yīng)用程序的功能,需要的朋友可以參考下
    2024-06-06

最新評(píng)論

会同县| 宜都市| 和硕县| 灵璧县| 大关县| 克什克腾旗| 浏阳市| 安平县| 大石桥市| 公安县| 普宁市| 阿勒泰市| 五原县| 永嘉县| 宁安市| 安国市| 沙田区| 宜兰市| 丹凤县| 久治县| 双江| 吕梁市| 青河县| 南江县| 乳山市| 博白县| 锦屏县| 宜丰县| 阜新市| 水富县| 绥棱县| 临潭县| 通渭县| 长子县| 南丹县| 东丽区| 清新县| 长丰县| 武山县| 游戏| 台州市|