java中BCryptPasswordEncoder密码的加密与验证方式
作者:DMY小天天
java BCryptPasswordEncoder密码的加密与验证
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),第一个参数是前端传递过来的明文密码,如123456,第二个参数是添加用户时存储的密码
if(bcp.matches(mm_pub,mm_encode)){
System.out.println("密码校验成功");
}else{
System.out.println("密码错误");
}
}
}BCryptPasswordEncoder加密、验证策略
通过查看源码,了解PasswordEncoder加密以及验证密码(数据库存储的加密密码与用户输入的密码比较)的流程、方式。
加密
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);//根据 明文密码 ,盐(随机) 然后生成加密密码
}BCryptPasswordEncoder类有三个构造方法,影响了盐的生成,如果在生成BCryptPasswordEncoder对象的时候没有指定任何参数(或只指定了一个参数),BCrypt会提供默认值,最终都会调用BCrypt.gensalt(strength, random)方法来生成盐。
接着看BCrypt类的hashpw()方法,在这个方法中根据salt值和明文密码来生成密文密码。
具体的生成细节就不再展示了,有兴趣的可以自己去看。
需要记住的是,它是先 生成盐值,根据盐值以及明文密码 生成密文。
解密
因为匹配方法里面用到解密
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:从数据库 中获取的 已加密的密码(例如数据库中加密过的密码:“$2a$10$3HY7qAX3Hry.6uuipvWjs.liaOjCIxw93SWxYaviQygwVg3VzUqHq”(反正看不懂,这个加密密码里面有一部分是 盐)
“$2a$10$3HY7qAX3Hry.6uuipvWjs.liaOjCIxw93SWxYaviQygwVg3VzUqHq” 就是用明文 123456 加密
如果表单密码和数据库加密密码匹配,则返回true
如果不匹配,则返回false。
因为上面的matches()方法最后是调用checkpw(),所以我们来看一下
public static boolean checkpw(String rawPassword, String encodedPassword) {
return equalsNoEarlyReturn(encodedPassword, hashpw(rawPassword, encodedPassword));
}hashpw()这个上面说过了,就是根据 明文密码 盐 ,然后生成加密密码
- encodedPassword: 数据库的密文密码
- hashpw(rawPassword, encodedPassword)):把表单的密码和数据库的密文密码 加密 成 新的密文密码
然后再把这个 新的密文密码 和 数据库的密文密码 比较,如果相同就返回true。
就是说 数据库的密文密码 本身不会被解码
只是用表单的密码通过某种规则加密成新的密码,然后再把新的密码和数据库的密文密码做比较。
如果有小伙伴想研究的更深的话,可以继续看一下源码。
下面我给大家看一下我的的例子
只是Controller里面的一个方法,至于service,dao层 自己写啦,这应该都会
/*
* 新建、修改用户
* */
@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());//从数据库查找数据
boolean isMatch=encoder.matches(user.getPassword(),DbUser.getPassword());//第一个参数是表单的密码(未加密的),第二个是数据库里面已经加密过的密码
if(!isMatch){
//因为要改密码,所以把表单的密码加密
String encodePassword=encoder.encode(user.getPassword());
user.setPassword(encodePassword);
}else{
user.setPassword(DbUser.getPassword());//虽然密码没变,但是这个表单user也要保存到数据库,要么把表单密码加密放进数据库,要么就直接用数据库原本的加密密码
}
}
userService.saveOrUpdateUser(user);//把这个user保存到数据库
return "添加或修改用户成功";
}总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
