一、Shiro
为什么要用shiro:
1.项目中的密码是否可以明文存储?
2.是否任意访客,无论是否登录都可以访问任何功能?
3.项目中的各种功能操作,是否是所有用户都可以随意使用?
综上,当项目中的某些功能被使用时,需要进行安全校验,进而保证整个系统的运行秩序。
1.1 Shiro是什么
- Apache Shiro 是 Java 的一个安全(权限)框架。
- Shiro 可以轻松的完成:身份认证、授权、加密、会话管理等功能
- Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE 环境,也可以用在 JavaEE 环境。
- 功能强大且易用,可以快速轻松地保护任何应用程序 ( 从最小的移动应用程序到最大的Web和企业应用程序。)
- 方便的与Web 集成和搭建缓存。
- 下载:http://shiro.apache.org/
1.2 功能简介
• 基本功能点如下图所示:
• Authentication
身份认证/登录,验证用户是不是拥有相应的身份;
• Authorization
授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能进行什么操作
如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
• Session Manager
会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有
信息都在会话中;会话可以是普通 JavaSE 环境,也可以是 Web 环境的;
• Cryptography
加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
• Web Support
Web 支持,可以非常容易的集成到Web 环境;
• Caching
缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
• Remember Me
记住我,这个是非常常见的功能,即一次登录后,下次再来的话可以立即知道你是哪个用户
。。。。
二、Shiro 架构
2.1 工作流程
shiro 运行流程中,3个核心的组件:
Subject、SecutiryManager、Realm
shiro使用中,必须有的3个概念!!
• Subject
安全校验中,最常见的问题是"当前用户是谁?" "当前用户是否有权做x事?",所以考虑安全校验过程最自
然的方式就是基于当前用户。Subject 代表了当前“用户”,
应用代码直接交互的对象是 Subject,只要得到Subject对象马上可以做绝大多数的shiro操作。
也就是说 Shiro 的对外API 核心就是 Subject。
Subject 会将所有交互都会委托给 SecurityManager。
==Subject是安全管理中直接操作的对象==
• SecurityManager
安全管理器;即所有与安全有关的操作都会与SecurityManager 交互;
且其管理着所有 Subject;它是 Shiro的核心,
它负责与 Shiro 的其他组件进行交互,它相当于 SpringMVC 中DispatcherServlet 的角色
• Realm
Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说SecurityManager 要验证用户身份,那么
它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;
也需要从 Realm 得到用户相应的角色/权限进行验证用户是否能进行操作;
可以把 Realm 看成 DAO,( 数据访问入口 )
2.2 RBAC模型
Role Base Access Controll 基于角色的访问控制
shiro采用的安全管理 模型
模型中3个主体:用户、角色、权限
每个角色可以有多个权限,每个权限可以分配给多个角色
每个用户可以有多个角色,每个角色可以分配给多个用户
两个多对多
则权限访问控制,做的事是:
- 身份校验:判断是否为合法用户
- 权限校验:用户要做做某件事或使用某些资源,必须要拥有某角色,或必须拥有某权限
在访问控制管理过程中,是要对项目中的资源(功能,数据,页面元素等)的访问、使用进行安全管理。
1> 首先照旧记录用户信息
2> 然后制定角色
3> 然后会对"资源"制定权限:即能对资源做的所有操作
4> 然后将权限分配给不同角色
5> 最后将角色分配给具体用户
6> 如此完成对 用户(李四,张三)使用某资源的访问控制
2.3 架构
• Subject
任何可以与应用交互的“用户”;
• SecurityManager
相当于SpringMVC 中的 DispatcherServlet;是 Shiro 的心脏;
所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进行认证、授权、会话及
缓存的管理。
• Authenticator
负责 Subject 身份认证,是一个扩展点,可以自定义实现;可以使用认证
策略(Authentication Strategy),即什么情况下算用户认证通过了;
• Authorizer
授权器、即访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;
• Realm
可以有 1 个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体
的;可以是JDBC 实现,也可以是内存实现等等;由用户提供;所以一般在应用中都需要
实现自己的 Realm;
• SessionManager
管理 Session 生命周期的组件;而 Shiro 并不仅仅可以用在 Web环境,也可以用在如普通的 JavaSE 环境
• CacheManager
缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少改变,
放到缓存中后可以提高访问的性能
• Cryptography
密码模块,Shiro 提供了一些常见的加密组件用于如密码加密/解密。
三、实际案例操作【重点】
这里我们根据【RBAC】模型设计五张简单的表,分别是用户表、角色表、权限表和两张中间表。
两个用户——李四是管理员,张三是普通用户
两个角色——管理员和普通用户
四个权限——对信息的增删改查
3.1 我们需要明确shiro在项目中的使用逻辑
3.2 导入相关的依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--所有的spring项目都会依赖logging,所以必须导入-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
3.3 web.xml配置
xml文件配置完成后建议重启服务器,不要重新部署
该配置必须放到所有工厂之前
<!--
1.项目的最外层构件访问控制层
2.在项目启动时初始化shiro环境,与spring和springmvc工厂一起启动
-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
在项目启动时,加载web-info 或 classpath下的 shiro.ini ,并构建WebSecurityManager。
构建所有配置中使用的过滤器链(anon,authc等),ShiroFilter会获取此过滤器链
-->
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
启动Shiro的原理
xml配置文件中,通过EnvironmentLoaderListener启动shiroFilter,实际上会经过以下几个步骤
//1. 创建 "SecurityFactory",加载ini配置,并通过它创建SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2. shiro核心:SecurityManager
SecurityManager securityManager = factory.getInstance();
//3. 托管到SecurityUtils工具类中(ops:之后可以不必关心SecurityManager)
SecurityUtils.setSecurityManager(securityManager);
这样,外部只需要调取SecurityUtils中的subject方法,获取subject对象即可,然后就可以进行各种判断处理。
- 通过在ini中设置的 身份信息、角色、权限,做安全管理
- 1.身份认证: subject.login(token)
- 2.是否认证身份判断:subject.isAuthenticated()
- 3.角色校验:subject.hasRole(String:role); subject.hasRoles(List:roles)
- 4.权限校验:subject.isPermitted(String:perm); subject.isPermittedAll(List:perms)
//4. 获取subject,直接由用户使用,调用功能简单,其底层调用Securitymanager的相关流程
Subject subject = SecurityUtils.getSubject();
//登录
//获取token
UsernamePasswordToken token = new UsernamePasswordToken("lisi", "456");
//根据token登录
subject.login(token);
//查看是否登录
System.out.println("是否登录?" + subject.isAuthenticated());
System.out.println("用户凭证(用户名) " + subject.getPrincipal())