1.导入相关依赖
相关依赖导入
。进口
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-testartifactId>
<scope>testscope>
dependency>
2.r简介
在项目中我们经常会用到密码加密
提供一个加密类r,可用于对密码字符串进行加密,并得到加密后的字符串。它使用的是hash算法
SHA-256
+随机哈希值+密钥对密码进行加密,更安全。 对于同一个密码,加密后得到的内容也不同,但是这相对于其他加密算法也增加了性能开销。
那么我们平时使用的加密算法和哈希算法有什么区别呢?
加密算法是可逆算法。 其基本过程就是将原本是明文的文件或数据按照一定的算法进行处理,使其成为一段不可读的代码,称为“密文”,但使用相应的密钥对其进行操作。 然后就可以得到原来的内容了
。
哈希算法是一种不可逆的算法,通过哈希算法将任意长度的输入转换为固定长度的输出。 输出是哈希值。 不同的输入可能散列成相同的输出,因此不可能从散列值进行散列。 列值来确定唯一的输入值。
不了解Hash算法的同学可以看看我的另一篇博客,里面详细介绍了Hash算法和求和的过程。 有一些图可以帮助大家记住。
数据结构要点------哈希表和java
一般业务流程中,首先前端用户填写注册信息并提交后,账户信息先到layer,然后依次经过layer和dao层,最后存入数据库。 密码的加密应该在层上完成,密码在存储到数据库之前应该被加密。
存在
,r接口可用于对密码进行加密,调用该方法返回一个加密字符串。 加密后,将加密后的字符串存储在数据库中。
虽然在使用的时候可以直接从配置文件中配置一个加密类bean,这样就可以直接注入,但是在实际项目中,它被封装在一个公共的工具类中,这样我们调用起来更加方便
注册时调用密码加密的方法
公共工具类中怎么写
/**
* 密码加密
* 在公共工具类中的写法
* @param password
* 未加密文本
* @return 加密后的文本
*/
public static String QuickPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
r中方法的源代码
我们看到该方法首先根据一定的规则获取一个Hash值(也就是代码中的salt。至于为什么要用salt,估计是写源码的大叔口味重了,感觉那个salt比较宽松,毕竟不能用数字),然后调用.()的时候,传入明文密码和哈希值。
public String encode(CharSequence rawPassword) {
String salt;
if (this.strength > 0) {
if (this.random != null) {
salt = BCrypt.gensalt(this.strength, this.random);
} else {
salt = BCrypt.gensalt(this.strength);
}
} else {
salt = BCrypt.gensalt();
}
return BCrypt.hashpw(rawPassword.toString(), salt);
}
接下来我们看看康义康对.()做了什么。 在该方法中,我们首先根据传入的哈希值通过规则从盐中获取哈希值。 后续的操作都是用这个来进行哈希,最终得到加密。 细绳。
注意:传入的salt并不是最终用于加密的Hash值。 是通过方法中的salt获取的,因为在后续的登录匹配方法中会用到这个。 ()是加密和解密过程中使用的方法。
public static String hashpw(String password, String salt) throws IllegalArgumentException {
char minor = 0;
int off = false;
StringBuilder rs = new StringBuilder();
if (salt == null) {
throw new IllegalArgumentException("salt cannot be null");
} else {
int saltLength = salt.length();
if (saltLength < 28) {
throw new IllegalArgumentException("Invalid salt");
} else if (salt.charAt(0) == '$' && salt.charAt(1) == '2') {
byte off;
if (salt.charAt(2) == '$') {
off = 3;
} else {
minor = salt.charAt(2);
if (minor != 'a' || salt.charAt(3) != '$') {
throw new IllegalArgumentException("Invalid salt revision");
}
off = 4;
}
if (saltLength - off < 25) {
throw new IllegalArgumentException("Invalid salt");
} else if (salt.charAt(off + 2) > '$') {
throw new IllegalArgumentException("Missing salt rounds");
} else {
int rounds = Integer.parseInt(salt.substring(off, off + 2));
String real_salt = salt.substring(off + 3, off + 25);
byte[] passwordb;
try {
passwordb = (password + (minor >= 'a' ? "\u0000" : "")).getBytes("UTF-8");
} catch (UnsupportedEncodingException var13) {
throw new AssertionError("UTF-8 is not supported");
}
byte[] saltb = decode_base64(real_salt, 16);
BCrypt B = new BCrypt();
byte[] hashed = B.crypt_raw(passwordb, saltb, rounds);
rs.append("$2");
if (minor >= 'a') {
rs.append(minor);
}
rs.append("$");
if (rounds < 10) {
rs.append("0");
}
rs.append(rounds);
rs.append("$");
encode_base64(saltb, saltb.length, rs);
encode_base64(hashed, bf_crypt_ciphertext.length * 4 - 1, rs);
return rs.toString();
}
} else {
throw new IllegalArgumentException("Invalid salt version");
}
}
}
登录流程工具
/**
* 校验密码正确错误
*
* @param rawPassword
* 未加密文本
* @param encodedPassword
* 加密文本
* @return true:密码正确 ,false密码错误
*/
public static Boolean checkPassword(String rawPassword, String encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword);
}
r中的调用方法
该方法用于判断明文是否对应于加密字符串。
在该方法中,首先对密文字符串进行一些验证。 如果不符合规则,则直接返回不匹配,然后调用验证方法。 第一个参数是明文,第二个参数是加密后的字符串。
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (encodedPassword != null && encodedPassword.length() != 0) {
if (!this.BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
this.logger.warn("Encoded password does not look like BCrypt");
return false;
} else {
return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
}
} else {
this.logger.warn("Empty encoded password");
return false;
}
}
然后调用方法,明文,密文,然后将明文和密文都传入方法(,),最后比较是否相等。
public static boolean checkpw(String plaintext, String hashed) {
return equalsNoEarlyReturn(hashed, hashpw(plaintext, hashed));
}
static boolean equalsNoEarlyReturn(String a, String b) {
char[] caa = a.toCharArray();
char[] cab = b.toCharArray();
if (caa.length != cab.length) {
return false;
} else {
byte ret = 0;
for(int i = 0; i < caa.length; ++i) {
ret = (byte)(ret | caa[i] ^ cab[i]);
}
return ret == 0;
}
}