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ù)是前端傳遞過來的明文密碼,如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)證策略
通過查看源碼,了解PasswordEncoder加密以及驗(yàn)證密碼(數(shù)據(jù)庫存儲(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í)候沒有指定任何參數(shù)(或只指定了一個(gè)參數(shù)),BCrypt會(huì)提供默認(rèn)值,最終都會(huì)調(diào)用BCrypt.gensalt(strength, random)方法來生成鹽。
接著看BCrypt類的hashpw()方法,在這個(gè)方法中根據(jù)salt值和明文密碼來生成密文密碼。
具體的生成細(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ù)庫 中獲取的 已加密的密碼(例如數(shù)據(jù)庫中加密過的密碼:“$2a$10$3HY7qAX3Hry.6uuipvWjs.liaOjCIxw93SWxYaviQygwVg3VzUqHq”(反正看不懂,這個(gè)加密密碼里面有一部分是 鹽)
“$2a$10$3HY7qAX3Hry.6uuipvWjs.liaOjCIxw93SWxYaviQygwVg3VzUqHq” 就是用明文 123456 加密
如果表單密碼和數(shù)據(jù)庫加密密碼匹配,則返回true
如果不匹配,則返回false。
因?yàn)樯厦娴膍atches()方法最后是調(diào)用checkpw(),所以我們來看一下
public static boolean checkpw(String rawPassword, String encodedPassword) {
?? ??? ?return equalsNoEarlyReturn(encodedPassword, hashpw(rawPassword, encodedPassword));
}hashpw()這個(gè)上面說過了,就是根據(jù) 明文密碼 鹽 ,然后生成加密密碼
- encodedPassword: 數(shù)據(jù)庫的密文密碼
- hashpw(rawPassword, encodedPassword)):把表單的密碼和數(shù)據(jù)庫的密文密碼 加密 成 新的密文密碼
然后再把這個(gè) 新的密文密碼 和 數(shù)據(jù)庫的密文密碼 比較,如果相同就返回true。
就是說 數(shù)據(jù)庫的密文密碼 本身不會(huì)被解碼
只是用表單的密碼通過某種規(guī)則加密成新的密碼,然后再把新的密碼和數(shù)據(jù)庫的密文密碼做比較。
如果有小伙伴想研究的更深的話,可以繼續(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ù)庫查找數(shù)據(jù)
boolean isMatch=encoder.matches(user.getPassword(),DbUser.getPassword());//第一個(gè)參數(shù)是表單的密碼(未加密的),第二個(gè)是數(shù)據(jù)庫里面已經(jīng)加密過的密碼
if(!isMatch){
//因?yàn)橐拿艽a,所以把表單的密碼加密
String encodePassword=encoder.encode(user.getPassword());
user.setPassword(encodePassword);
}else{
user.setPassword(DbUser.getPassword());//雖然密碼沒變,但是這個(gè)表單user也要保存到數(shù)據(jù)庫,要么把表單密碼加密放進(jìn)數(shù)據(jù)庫,要么就直接用數(shù)據(jù)庫原本的加密密碼
}
}
userService.saveOrUpdateUser(user);//把這個(gè)user保存到數(shù)據(jù)庫
return "添加或修改用戶成功";
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java8使用filter()取出自己所需數(shù)據(jù)
這篇文章主要介紹了java8使用filter()取出自己所需數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
Java拖曳鼠標(biāo)實(shí)現(xiàn)畫線功能的方法
這篇文章主要介紹了Java拖曳鼠標(biāo)實(shí)現(xiàn)畫線功能的方法,需要的朋友可以參考下2014-07-07
Java實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)IO版本
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)IO版本,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04
SpringBoot?AOP統(tǒng)一處理Web請(qǐng)求日志的示例代碼
springboot有很多方法處理日志,例如攔截器,aop切面,service中代碼記錄等,下面這篇文章主要給大家介紹了關(guān)于SpringBoot?AOP統(tǒng)一處理Web請(qǐng)求日志的相關(guān)資料,需要的朋友可以參考下2023-02-02
AbstractProcessor擴(kuò)展MapStruct自動(dòng)生成實(shí)體映射工具類
這篇文章主要為大家介紹了AbstractProcessor擴(kuò)展MapStruct自動(dòng)生成實(shí)體映射工具類實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Spring中使用Hystrix實(shí)現(xiàn)熔斷詳解
這篇文章主要介紹了Java中使用Hystrix實(shí)現(xiàn)熔斷詳解,對(duì)于第一個(gè)問題,查看hystrix源碼可以看到,如果有緩存配置是優(yōu)先使用的緩存的,因此如果配置更新,必須要更新緩存,不能使用Hystrix.reset()方法來更新緩存,需要的朋友可以參考下2023-12-12

