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層 自己寫啦,這應(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)文章
java9版本特性資源自動(dòng)關(guān)閉的語(yǔ)法增強(qiáng)
這篇文章主要為大家介紹了java9版本特性資源自動(dòng)關(guān)閉的語(yǔ)法增強(qiáng)的詳細(xì)使用說(shuō)明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
VsCode配置java環(huán)境的詳細(xì)圖文教程
vscode是一個(gè)免費(fèi)的代碼編輯器,支持多種主題,應(yīng)用起來(lái)簡(jiǎn)單方便,下面這篇文章主要給大家介紹了關(guān)于VsCode配置java環(huán)境的詳細(xì)圖文教程,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
SpringBoot之使用Redis實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng))
這篇文章主要介紹了SpringBoot之使用Redis實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
詳解SimpleDateFormat的線程安全問(wèn)題與解決方案
這篇文章主要介紹了SimpleDateFormat的線程安全問(wèn)題與解決方案,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03

