- 获取当前的Subject, 调用
SecurityUtils.getSubject()
; - 测试当前用户是否已经被认证, 即是否已经登录, 调用Subject的
isAuthentication()
- 若没有被认证, 则把用户名和密码封装为
UsernamePasswordToken
对象- 创建一个表单页面
- 把请求提交到Controller中
- 获取用户名和密码
- 前台执行登录, 调用Subject的
login(AuthenticationToken)
方法 - 自定义Realm, 从数据库中获取对应的记录, 返回给Shiro
- 自定义的Realm需要继承
org.apache.shiro.realm.AuthorizingRealm
类 - 实现
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
方法 - 实现方法中的参数就是前台中login方法中的token
- 自定义的Realm需要继承
- 由shiro内部自动完成密码的比对
Controller 实现doGetAuthenticationInfo方法
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了->认证UserRealm.doGetAuthenticationInfo");
// 1. 把AuthenticationToken 转为 UsernamePasswordToken
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
// 2. 从数据库中获取用户: userToken.getUsername()就是前台用户输入的用户名
User user = userService.queryUserByName(userToken.getUsername());
// 3. 用户不存在, 抛出异常
if (user == null) {
return null; // 抛出异常 UnknowAccountException
}
// 4. 根据用户的情况,来构建 AuthenticationInfo对象并返回,常常使用SimpleAuthenticationInfo
// arg1: principal: 认证的实体信息,可以是username,也可以是数据表中对应用户的实体类
// arg2: credentials: 密码,shiro底层自动帮我们做比对了
// arg3: realName: 当前realm对象的name, 调用父类的getName()即可
return new SimpleAuthenticationInfo(user, user.getPwd(), "");
}
- 在Controller中封装的token(封装了用户的信息), 为什么和我们重写的
doGetAuthenticationInfo
方法参数是同一个对象;
首先从Controller中subject.login(token)
的login方法点进去一直找(如下图)
找到
AuthenticatingRealm
类中的方法, 其中就调用了我们重写的doGetAuthenticationInfo(token)
方法, 即将用户封装的信息传递了过去!
授权流程
- 自定义的Realm继承
AuthorizingRealm
类实现protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
方法