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使用哈希算法+随机盐来对字符串加密。因为哈希是一种不可逆算法,所以密码认证时需要使用相同的算法+盐值来对待校验的明文进行加密,然后比较这两个密文来进行验证。

posted @ 2021-04-02 19:29  当康  阅读(1134)  评论(0编辑  收藏  举报