1.Shiro简介
Apache Shiro 是 Java 的一个安全框架。Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与Web应用集成、缓存等。
2 .Shiro系统架构
和应用代码直接交互的对象是 Subject ,Shiro的对外API核心就是 Subject ;
其每个API的含义:
-
Subject(主体)
代表了当前用户 所有 Subject都绑定到SecurityManager,与 Subject 的所有交互都会委托SecurityManager。 -
SecurityManager(安全管理器)
即所有与安全有关的操作都会与SecurityManager交互安全管理器管理所有Subject ,它是Shiro的核心,它负责与后边介绍的其他组件进行交互。 -
Realm
Shiro从Realm获取安全数据(如用户、角色、权限),SecurityManager要认证用户身份,需要从Realm获取用户信息进行比较以确定用户身份是否合法。
总结,最简单的一个 Shiro 应用:
应用代码通过 Subject 来进行认证和授权,而Subject又委托给SecurityManager
我们需要给Shiro的SecurityManager注入Realm ,从而让SecurityManager能得到合法的用户及其权限进行判断。
3.shiro核心对象
-
Subjec
从上图可以看到,主体可以是任何可以与应用交互的用户,Subject 通过SecurityManager安全管理器进行认证授权。 -
SecurityManage
所有具体的交互都通SecurityManage进行控制;它管理着所Subject、负责进行认证和授权、及会话、缓存的管理。 -
Authenticator(认证器)
对主体(用户)身份进行认证。 -
Authorizer(授权器)
用户通过认证器认证通过后,用来决定主体是否有权限进行相应的操作即控制着用户能访问应用中的哪些功能。 -
Realm
SecurityManage进行安全认证需要通Realm获取用户权限数据。Shiro不知道你的用户/权限存储在哪及以何种格式存储,所以我们一般在应用中都需要实现自己的Realm。 -
SessionManager(会话管理器)
shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。 -
SessionDAO
DAO,数据访问对象,用于会话的 CRUD,如果把 Session 保存到数据库,可以实现自己的 SessionDAO,通过如 JDBC 写到数据库如果把Session放到Redis中,可以实现自己的Redis SessionDAO。另外 SessionDAO 中可以使用Cache进行缓存,以提高性能。 -
CacheManager(缓存管理)
用来管理如用户、角色、权限等的缓存信息,因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能。 -
Cryptography
密码管理器 -
Cryptograph
密码模块,Shiro提供了一些常见的加密组件用于如密码加密。
4.入门案例
1.创建一个maven工程,在pom.xml中添加以下依赖
<dependencies>
<!--shiro核心包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--slf4j与log4j2桥接-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.1</version>
</dependency>
</dependencies>
2.配置日志和shiro.ini
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--先定义所有的appender-->
<appenders>
<!--输出控制台的配置-->
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<!--<patternlayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%p] %c %m
%n"/>-->
<patternlayout pattern="[%p] %m %n"/>
</console>
</appenders>
<!-- 然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
<!-- 日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE >
ALL -->
<loggers>
<root level="ERROR">
<!--输出到控制台-->
<appender-ref ref="Console"/>
</root>
<!--org.springframework
<logger name="org.springframework" level="INFO"/>-->
</loggers>
</configuration>
shiro.ini
[users]
zhangsan=1234,admin
lishi=4321,public
[roles]
admin=product:create,product:delete,product:update,product:view
public=product:view
3.测试代码
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
public class ShiroTest {
@Test
public void test1(){
//1.初始化shiro的安全管理器
SecurityManager securityManager =new DefaultSecurityManager(new IniRealm("classpath:shiro.ini"));
//2.使用SecurityUtils将securityManager设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
//3. 创建一个Subject实例,该实例认证要使用上边创建的securityManager进行
Subject subject = SecurityUtils.getSubject();
//4. 创建token令牌,记录用户认证的身份和凭证即账号和密码
AuthenticationToken token = new UsernamePasswordToken("zhangsan","1234");
//5. 用户登录认证
System.out.println("用户认证状态:"+subject.isAuthenticated());
subject.login(token);
//6. 用户认证状态
System.out.println("用户认证状态:"+subject.isAuthenticated());
//7. 用户角色授权状态
System.out.println("是否拥有admin角色:"+subject.hasRole("admin"));
System.out.println("是否拥有public角色:"+subject.hasRole("public"));
//8. 用户资源授权状态
System.out.println("是否拥有创建产品权限:"+subject.isPermitted("product:create"));
//9.获取用户信息
System.out.println("用户名:"+subject.getPrincipal());
//10.退出登录
subject.logout();
System.out.println("用户认证状态:"+subject.isAuthenticated());
}
}
控制台输出