Shiro的登录步骤
1. 获取当前的Subject,调用SecurityUtils.getSubject();
2.测试当前的用户是否已被认证,即是否已经登录,调用Subject的isAuthenticationed();
3.若没有被认证,则把用户名和密码封装为 UsernamePasswordToken对象。
(1)创建一个表单页面。
(2)把请求提交到SpringMVC的Handler
(3)获取用户名和密码
4.执行登录:调用Subject的login(AuthenticationToken token)的方法。
5.自定义Ream方法,从数据库中获取对应的记录,返回给shiro。
(1)实现上需要继承org.apache.shiro.realm.AuthenticatingRealm类。
(2)实现 doGetAuthenticationInfo(Authentication token)方法。
6.由shiro完成对密码的比对
subject.login(token); //把token传入给自定义的Realm。
doGetAuthenticationInfo (AuthenticationToken token) 方法实现如下:
//1.把AuthenticationToken 转换为UsernamePasswordToken
UsernamePasswordToken token =(UsernamePasswordToken) token;
//2.从UsernamePasswordToken 中获取username
String username =token.getUsername();
//3.调用数据库方法,从数据库中查询username对应的用户记录
//省略
//4.若用户不存在,则可以抛出UnknowAccountException
if("unknow.equals(username)"){
throw new RuntimeException("用户不存在");
}
//5.根据用户信息的情况,决定是否需要抛出其他的AuthenticationException异常
if("monster.equals(username)"){
throw new RuntimeException("用户被锁定");
}
//6.根据用户的情况,来构建AuthenticationInfo对象返回
//以下是从数据库中获取
1)principal:认证实体信息,可以是username,也可以是数据表对应的用户实体类对象。
2)credentials:密码
3)realm:当前realm对象的name,调用父类的getName()方法即可。
SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(prinacipal,credentials,realmName);
密码的对比
通过AuthenticatingRealm的credenticalsMatcher属性来进行的密码比对
ByteSource credentialsSalt =ByteSource.Util.byte(username); //username为盐值
如何做到MD5盐值加密
1)在doGetAuthenticationInfo方法返回值创建SimpleAuthenticationInfo对象的时候需要使用SimpleAuthenticationInfo(principal,credentials,credentialsSalt,realmName)的构造器。
2)使用ByteSource.Util.bytes()来计算盐值。
3)盐值需要唯一:一般使用随机数字串或者userId
4)使用new SimpleHash(hashAlgorithmName,credentials,salt,hashIteration)来计算盐值加密后的密码的值
授权
1.授权需要继承AuthorizingRealm,并实现其doGetAuthorizationInfo方法
2.AuthorizingRealm类继承自AuthenticatingRealm,但没有实现AuthenticatingRelam中的doGetAuthenticationInfo,所以认证和授权只需要继承AuthorizingRelam就可以了。同时实现他的两个抽象方法。
过程:
1.从PrincipalCollection中来获取登陆用户的信息。
Object principal =principals.getPrimaryPrincipal();
2.利用登陆的用户的信息来用户当前用户的角色或权限(可能需要查询数据库)
Set<String> roles =new HashSet<>();
roles.add("user");
if("admin.equals(principal)"){
roles.add("admin");
}
3.创建SimpleAuthorizationInfo,并设置其roles属性。
SimpleAuthorizationInfo info =new SimpleAuthorizationInfo(roles);
4.返回SimpleAuthorizationInfo对象
return info;