Spring Security中关于BCryptPasswordEncoder的使用
Spring Security中关于BCryptPasswordEncoder的使用
加密算法和hash算法的区别
加密算法是一种可逆的算法,基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码为“密文”,但在用相应的密钥进行操作之后就可以得到原来的内容。
哈希算法是一种不可逆的算法,是把任意长度的输入通过散列算法变换成固定长度的输出,输出就是散列值,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。
常见的加密算法MD5只要是相同的salt和原密码,加密后产生的密串都是一致的,而Spring Security提供了BCryptPasswordEncoder这个加密算法类,使用相同的明文,生成的新的加密字符串都不一样。
源码解析
BCryptPasswordEncoder类实现了PasswordEncoder接口,这个接口中定义了两个方法
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
}
- encode()
对字符串进行加密的方法 - matches()
校验传入的明文密码rawPassword是否和加密密码encodedPassword相匹配
加密
public String encode(CharSequence rawPassword) {
String salt;
if (strength > 0) {
if (random != null) {
salt = BCrypt.gensalt(strength, random);
}
else {
salt = BCrypt.gensalt(strength);
}
}
else {
salt = BCrypt.gensalt();
}
return BCrypt.hashpw(rawPassword.toString(), salt);
}
基于某种规则得到了一个盐值(salt),然后调用BCrypt.hashpw方法,传入明文密码和salt,最终得到加密字符串(salt也保存在其中)。
比较
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);
}
先对密文字符串进行了一些校验,如果不符合规则直接返回不匹配,然后调用校验方法BCrypt.checkpw。
BCryptPasswordEncoder 判断密码是否相同
String pass = "123";
System.out.println("password is "+pass);
BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder();
for(int i=0;i<3;i++) {
System.out.println("第"+(i+1)+"次");
String hashPass = bcryptPasswordEncoder.encode(pass);
System.out.println("做加密:"+hashPass);
boolean flag = bcryptPasswordEncoder.matches("123", hashPass);
System.out.println("判断密码是否相同:"+flag);
}
结果:
password is 123
第1次
做加密:$2a$10$R7cLoVVvX/YrGfzdwxihjOb8FKYlthbqjq7XYuKYmonPvAd3toRWe
判断密码是否相同:true
第2次
做加密:$2a$10$YRHMd2MW/IVGm5mx5CyIhuex.eWYcYcwR0GdaMeVgk6Nz1nn2kZpS
判断密码是否相同:true
第3次
做加密:$2a$10$8xovulGLu8n8vdk9aVBBjO92c8ZNa7KYt4YJSJBrlUhbOOU2meZfi
判断密码是否相同:true
每次输出的hashPass 都不一样,但是最终的flag都为 true,即匹配成功。
总结
BCryptPasswordEncoder使用哈希算法+随机盐来对字符串加密。因为哈希是一种不可逆算法,所以密码认证时需要使用相同的算法+盐值来对待校验的明文进行加密,然后比较这两个密文来进行验证。