java中BCryptPasswordEncoder密碼的加密與驗(yàn)證方式
java BCryptPasswordEncoder密碼的加密與驗(yàn)證
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; public class Test{ public static void main(String[] args) { BCryptPasswordEncoder bcp = new BCryptPasswordEncoder(); String mm_pub = "123456"; String mm_encode = bcp.encode(mm_pub); //bcp.matches(mm_pub,mm_encode),第一個(gè)參數(shù)是前端傳遞過(guò)來(lái)的明文密碼,如123456,第二個(gè)參數(shù)是添加用戶時(shí)存儲(chǔ)的密碼 if(bcp.matches(mm_pub,mm_encode)){ System.out.println("密碼校驗(yàn)成功"); }else{ System.out.println("密碼錯(cuò)誤"); } } }
BCryptPasswordEncoder加密、驗(yàn)證策略
通過(guò)查看源碼,了解PasswordEncoder加密以及驗(yàn)證密碼(數(shù)據(jù)庫(kù)存儲(chǔ)的加密密碼與用戶輸入的密碼比較)的流程、方式。
加密
public String encode(CharSequence rawPassword) { String salt; if (random != null) { salt = BCrypt.gensalt(version.getVersion(), strength, random);//生成鹽 } else { salt = BCrypt.gensalt(version.getVersion(), strength);//生成鹽 } return BCrypt.hashpw(rawPassword.toString(), salt);//根據(jù) 明文密碼 ,鹽(隨機(jī)) 然后生成加密密碼 }
BCryptPasswordEncoder類有三個(gè)構(gòu)造方法,影響了鹽的生成,如果在生成BCryptPasswordEncoder對(duì)象的時(shí)候沒(méi)有指定任何參數(shù)(或只指定了一個(gè)參數(shù)),BCrypt會(huì)提供默認(rèn)值,最終都會(huì)調(diào)用BCrypt.gensalt(strength, random)方法來(lái)生成鹽。
接著看BCrypt類的hashpw()方法,在這個(gè)方法中根據(jù)salt值和明文密碼來(lái)生成密文密碼。
具體的生成細(xì)節(jié)就不再展示了,有興趣的可以自己去看。
需要記住的是,它是先 生成鹽值,根據(jù)鹽值以及明文密碼 生成密文。
解密
因?yàn)槠ヅ浞椒ɡ锩嬗玫浇饷?/p>
BCryptPasswordEncoder的matches()方法代碼如下:
public boolean matches(CharSequence rawPassword, String encodedPassword) { if (encodedPassword == null || encodedPassword.length() == 0) { logger.warn("Empty encoded password"); return false; } if (!BCRYPT_PATTERN.matcher(encodedPassword).matches()) { logger.warn("Encoded password does not look like BCrypt"); return false; } return BCrypt.checkpw(rawPassword.toString(), encodedPassword); }
- rawPassword :提交表單的用戶密碼,就是未加密的,例如表單提交為:123456
- encodedPassword:從數(shù)據(jù)庫(kù) 中獲取的 已加密的密碼(例如數(shù)據(jù)庫(kù)中加密過(guò)的密碼:“$2a$10$3HY7qAX3Hry.6uuipvWjs.liaOjCIxw93SWxYaviQygwVg3VzUqHq”(反正看不懂,這個(gè)加密密碼里面有一部分是 鹽)
“$2a$10$3HY7qAX3Hry.6uuipvWjs.liaOjCIxw93SWxYaviQygwVg3VzUqHq” 就是用明文 123456 加密
如果表單密碼和數(shù)據(jù)庫(kù)加密密碼匹配,則返回true
如果不匹配,則返回false。
因?yàn)樯厦娴膍atches()方法最后是調(diào)用checkpw(),所以我們來(lái)看一下
public static boolean checkpw(String rawPassword, String encodedPassword) { ?? ??? ?return equalsNoEarlyReturn(encodedPassword, hashpw(rawPassword, encodedPassword)); }
hashpw()這個(gè)上面說(shuō)過(guò)了,就是根據(jù) 明文密碼 鹽 ,然后生成加密密碼
- encodedPassword: 數(shù)據(jù)庫(kù)的密文密碼
- hashpw(rawPassword, encodedPassword)):把表單的密碼和數(shù)據(jù)庫(kù)的密文密碼 加密 成 新的密文密碼
然后再把這個(gè) 新的密文密碼 和 數(shù)據(jù)庫(kù)的密文密碼 比較,如果相同就返回true。
就是說(shuō) 數(shù)據(jù)庫(kù)的密文密碼 本身不會(huì)被解碼
只是用表單的密碼通過(guò)某種規(guī)則加密成新的密碼,然后再把新的密碼和數(shù)據(jù)庫(kù)的密文密碼做比較。
如果有小伙伴想研究的更深的話,可以繼續(xù)看一下源碼。
下面我給大家看一下我的的例子
只是Controller里面的一個(gè)方法,至于service,dao層 自己寫(xiě)啦,這應(yīng)該都會(huì)
/* * 新建、修改用戶 * */ @PostMapping @ResponseBody public String saveUser(User user){ PasswordEncoder encoder=new BCryptPasswordEncoder(); if(user.getId()==null){ //新增用戶,所以把表單的密碼加密一下 String encodePassword=encoder.encode(user.getPassword()); user.setPassword(encodePassword); }else{ //判斷密碼是否做了修改 User DbUser=userService.getUserById(user.getId());//從數(shù)據(jù)庫(kù)查找數(shù)據(jù) boolean isMatch=encoder.matches(user.getPassword(),DbUser.getPassword());//第一個(gè)參數(shù)是表單的密碼(未加密的),第二個(gè)是數(shù)據(jù)庫(kù)里面已經(jīng)加密過(guò)的密碼 if(!isMatch){ //因?yàn)橐拿艽a,所以把表單的密碼加密 String encodePassword=encoder.encode(user.getPassword()); user.setPassword(encodePassword); }else{ user.setPassword(DbUser.getPassword());//雖然密碼沒(méi)變,但是這個(gè)表單user也要保存到數(shù)據(jù)庫(kù),要么把表單密碼加密放進(jìn)數(shù)據(jù)庫(kù),要么就直接用數(shù)據(jù)庫(kù)原本的加密密碼 } } userService.saveOrUpdateUser(user);//把這個(gè)user保存到數(shù)據(jù)庫(kù) return "添加或修改用戶成功"; }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java8使用filter()取出自己所需數(shù)據(jù)
這篇文章主要介紹了java8使用filter()取出自己所需數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Java拖曳鼠標(biāo)實(shí)現(xiàn)畫(huà)線功能的方法
這篇文章主要介紹了Java拖曳鼠標(biāo)實(shí)現(xiàn)畫(huà)線功能的方法,需要的朋友可以參考下2014-07-07Java實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)IO版本
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)IO版本,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04SpringBoot?AOP統(tǒng)一處理Web請(qǐng)求日志的示例代碼
springboot有很多方法處理日志,例如攔截器,aop切面,service中代碼記錄等,下面這篇文章主要給大家介紹了關(guān)于SpringBoot?AOP統(tǒng)一處理Web請(qǐng)求日志的相關(guān)資料,需要的朋友可以參考下2023-02-02AbstractProcessor擴(kuò)展MapStruct自動(dòng)生成實(shí)體映射工具類
這篇文章主要為大家介紹了AbstractProcessor擴(kuò)展MapStruct自動(dòng)生成實(shí)體映射工具類實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Spring中使用Hystrix實(shí)現(xiàn)熔斷詳解
這篇文章主要介紹了Java中使用Hystrix實(shí)現(xiàn)熔斷詳解,對(duì)于第一個(gè)問(wèn)題,查看hystrix源碼可以看到,如果有緩存配置是優(yōu)先使用的緩存的,因此如果配置更新,必須要更新緩存,不能使用Hystrix.reset()方法來(lái)更新緩存,需要的朋友可以參考下2023-12-12