Shiro认证从精通到入门
Shiro的体系结构
- Authentication:认证,验证用户是否合法(登陆)
- Authorization: 授权(授予谁具有访问某些资源的权力)
- Session Manager :会话管理(管理用户登陆后的信息,不管是在什么应用中)
- Cryptography : 加密(提供了常见的加密算法)
- Web Support : web应用程序支持
- Caching : 缓存(支持多种缓存架构)
- Concurrency : 支持多线程并发访问
- Testing : 测试
- Run As : 支持一个用户在允许的情况下使用另外一个身份登陆
- Remember Me : 记住我
shiro的架构
- Subject : 主体,也可以是用户或第三方程序,用于获取主体信息
- Security Manager : 安全管理器,是Shiro架构的核心,协调各个组件工作
- Authenticator : 认证器,负责认证用户的身份
- Authorizer : 授权器,负责为合法用户指定其权限(控制用户可以访问哪些资源)
- Realms : 域,用户通过Shiro来完成相关的安全工作,Shiro是不会去维护数据信息的.在Shiro工作过程中.数据的查询和获取是通过Realm从不同的数据源来获取的.Realm可以获取数据库信息,文本信息等.在Shiro中可以有一个Realm也可以有多个.
用户认证
- Principals : 用户的身份信息,是Subject的属性标识.能唯一标识Subject .如:电话号码,电子邮箱,身份证号码
- Credentials : 凭证(密码).是只被subject知道的密码值.可以是密码,也可以是数字证书 (Principals/Credentials最常见的组合:用户名/密码.在Shiro中通常使用UsernamePasswordToken来指定身份和凭证信息)
编写 Helloworld
项目结构及jar包图示:
测试代码
package cn.ckh2019.shiro;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import java.security.Security;
/**
* @author Chen Kaihong
* 2019-06-08 20:40
*/
public class App {
public static void main(String[] args) {
//1,创建SecurityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2.通过SecurityManager工厂获取SecurityManager实例
SecurityManager securityManager = factory.getInstance();
//3.将securityManager对象设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//4.通过SecurityUtils获取主体Subject
Subject subject = SecurityUtils.getSubject();
//5.假如登陆的用户名 : ckh 和 1234
UsernamePasswordToken token = new UsernamePasswordToken("ckh","1234");
//6.进行用户验证
subject.login(token);
//7.通过subject来判断用户是否通过验证
if(subject.isAuthenticated()){
System.out.println("登录成功");
}
}
}
在classpath下新建一个名为shiro.ini 的文件,输入下面的内容,目的是模拟数据库的用户信息,
[users]
ckh=1234
异常处理
在测试代码的第7步中,subject.isAuthenticated()
判断用户是否通过验证,如果验证成功会返回true,执行下面的输出语句,但是需要注意的是,验证不通过的话是不会返回false的,而是会直接抛出异常,shiro也对验证不通过的不同种类的情况下提供了不同的异常类.
下面这张图是shiro提供的异常类
在认证过程中有一个父异常:AuthenticationException,该异常有几个子类,分别对应不同的异常情况
- DisabledAccountException : 账户失效异常
- ExcessiveAttemptsException : 尝试次数过多
- UnknownAccountException : 用户名错误
- ExpiredCredentException : 凭证过期
- IncorrectCredeException : 凭证不正确
因此可以针对不同的认证失败情况捕获不同的异常,或者甚至可以直接捕获他们的父异常AuthenticationException,例如:
try {
subject.login(token);
if (subject.isAuthenticated()) {
System.out.println("登录成功");
}
}catch(IncorrectCredentialsException e) {
System.out.println("密码错误");
}catch(UnknownAccountException e){
System.out.println("用户名错误");
}
总结认证的执行流程:
- 通过shiro的相关api,创建SecurityManager及其Subject对象
- 封装token信息
- 通过subject.login(token)进行用户认证
subject接收token,通过其实现类DelegatingSubject将token委托给SecurityManger来完成认证.SecurityManager是一个接口,通过实现类DefaultSecurityManager的login方法完成认证功能,在login中调用了改类authenticate()来完成认证.该方法是由AuthenticactingSecurityManager来完成的.在该类的authenticate()中,调用authenticator(认证器)来完成认证.Authenticator是由其默认的实现类ModularRealmAuthenticator来完成认证.通过ModularRealmAuthenticator中的doAuthenticte来获取Realms信息.如果是单realm,如果是多realm,那么需要通过Authentication Strategy来完成对应的认证工作. - 通过subject.isAuthenticated()判断是否认证成功