其他的的内容在这里
shiro框架简单介绍以及使用(一)
shiro框架的权限设定(三)
shiro框架的密码校验进阶(四)多登陆方式实现思路
上一篇简单介绍了一下shiro框架和账号验证,这篇简单写一下shiro密码校验的介绍和几种使用方式
一、加密/加盐介绍
-
什么是加密?什么是加盐?
1.加密:加密是以某种特殊的算法改变原有的信息数据,这样的话即使你拿到了密文,但因为你不知道加密方式也没办法知道密文的内容。比如说电报,你监听到了发的电报,但是你不知道用的是那个密码本,一样无法知道电报内容是什么。
2.加盐:加盐是指将每口令同一个叫做”盐“值相关联,我们这里用于密码加盐,盐值一般都是随机数。 -
为什么要加密加盐?
1.加密的作用我上面已经说了即使你拿到了密文,但因为你不知道加密方式也没办法知道密文的内容。
2.加盐的话是为了让相同的密码值不同,例如说你使用的md5加密方式,只要你的密码是相同的,那么你加密后的数据也是相同的,这样如果密码密文泄露,只需要找到相应的加密方式就能还原明文密码,如果我们使用加盐加密,盐值为随机数,这样即使密码相同密文也会不同,加大安全性
二、实现加密的方式
2.1shiro提供的密码校验接口
Shiro 提供了 PasswordService 接口及 CredentialsMatcher 接口 用于密码的校验服务
CredentialsMatcher接口用于验证密码
boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info);
这个方法的token就是从前台过来的token,你在登录页面输入的明文账号密码
info的值是从重写AuthorizingRealm的doGetAuthenticationInfo(AuthenticationToken token)的返回值
也就是我上一篇写的AuthRealm中的doGetAuthenticationInfo方法的返回值
return new SimpleAuthenticationInfo(upToken.getUsername(), upToken.getPassword(), “ShiroReaml”);
通过重写CredentialsMatcher接口的doCredentialsMatch()方法然后将两个参数的值进行比对就可以做密码校验了
/***
* @Description: 这块是登录验证配置
* @Param: [token]
* @return: org.apache.shiro.authc.AuthenticationInfo
* @Author: lizelin
* @Date: 2021/5/13 0013 1:25
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//AuthenticationToken转成UsernamePasswordToken这样可以直接拿到用户名和密码
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
//判断用户名是否为aaa否则抛出异常完事密码错误
if(!username.equals("aaa")){
throw new UnknownAccountException("用户错误");
}
return new SimpleAuthenticationInfo(upToken.getUsername(), upToken.getPassword(), "ShiroReaml");
PasswordService 用于加密密码
encryptPassword()方法为输入明文密码获得加密密文
passwordsMatch()方法为输入明文密码和输入加密密文进行比对
2.2shiro提供的密码校验实现
CredentialsMatcher提供的实现类:- SimpleCredentialsMatcher
- HashedCredentialsMatcher
- PasswordMatcher
这三个实现类中HashedCredentialsMatcher为SimpleCredentialsMatcher的实现类。
但是SimpleCredentialsMatcher为明文密码校验,所以我们不做考虑。
后面主要讲HashedCredentialsMatcher与PasswordMatcher。
相对于PasswordMatcher来说HashedCredentialsMatcher的功能更加强大
三、shiro通过HashedCredentialsMatcher来实现密码校验
那么理论讲的差不多了,我们直接开始撸代码,没有代码的话去看我的上一篇文章,拿里面的代码进行修改3.1将HashedCredentialsMatcher注入到securityManager中
我们需要将HashedCredentialsMatcher注入到AuthorizingRealm中才能使用 //将自己的验证方式加入容器
@Bean
public Realm AuthRealm() {
AuthRealm authRealm = new AuthRealm();
HashedCredentialsMatcher credentials= new HashedCredentialsMatcher();
credentials.setHashIterations(3);//加密次数
credentials.setHashAlgorithmName("MD5");//加密方式
authRealm.setCredentialsMatcher(credentials);//注入到AuthRealm实现类中
return authRealm;
}
将Shiro中的AuthRealm()方法修改注入HashedCredentialsMatcher实现类
3.2获得加密密文
这个因为我没连数据库,就模拟数据了,连接数据库也不难嗷,我把值都给你拿到,你放数据库就完事了到时候用户注册或者是修改密码的时候,将明文密码放进来,获得密文与盐放入数据库
/***
* @Description: 获得密文
* @Param:
* @return:
* @Author: lizelin
* @Date: 2021/5/14 0014 17:58
*/
@Component
public class CheckUtil{
public String encryption(HashedCredentialsMatcher Hashed, char[] passWord){
System.out.println("开始");
String random = new SecureRandomNumberGenerator().nextBytes().toHex();//获得随机数盐值
System.out.println(random);//打印盐值
ByteSource salt=ByteSource.Util.bytes(random);//将盐值转为ByteSource类型
System.out.println();
//获得加密后的密码
//SimpleHash hash = new SimpleHash("HashedCredentialsMatcher配置的加密方式","明文密码" , "盐值", "加密次数");
SimpleHash hash = new SimpleHash(Hashed.getHashAlgorithmName(), passWord, salt, Hashed.getHashIterations());
String encodedPassword = hash.toHex();
//打印加密后的密文
System.out.println(encodedPassword);
return "";
}
}
3.3跑起来获得盐和密文
首先打开我们的postman,然后访问username为:aaa
password为:ccc
获得了盐值:6186808fa1ad5ba0ef39a88c97e900df
和加密密文:90a1626d55503a2c2e7eb345a4f3a607
然后我们去修改doCredentialsMatch()方法进行测试
3.4将盐值注入HashedCredentialsMatcher进行模拟测试
@Autowired
CheckUtil check;
/***
* @Description: 这块是登录验证配置
* @Param: [token]
* @return: org.apache.shiro.authc.AuthenticationInfo
* @Author: lizelin
* @Date: 2021/5/13 0013 1:25
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//AuthenticationToken转成UsernamePasswordToken这样可以直接拿到用户名和密码
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
//判断用户名是否为aaa否则抛出异常完事密码错误
if(!username.equals("aaa")){
throw new UnknownAccountException("用户错误");
}
//这个3.3的测试写的,刚刚忘记写了
check.encryption((HashedCredentialsMatcher)getCredentialsMatcher(),upToken.getPassword());
//把盐放进来
ByteSource salt=ByteSource.Util.bytes("6186808fa1ad5ba0ef39a88c97e900df");
return new SimpleAuthenticationInfo(upToken.getUsername(), "90a1626d55503a2c2e7eb345a4f3a607", salt,getName());
//new SimpleAuthenticationInfo(登录的用户名,数据库查的加密密码,盐值, Realm名可以直接写getName()随便叫啥没所谓)
}
3.5测试密码加密以及校验是否正确
密码为ccc时登录成功,测试没毛病
密码为bbb时登录失败用户或密码不正确,测试没毛病