Shiro学习
Apache Shiro是一个开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时能提供健壮的安全性。
Shiro
1.Apache Shiro是一个强大且易用的Java安全框架,能够用于身份验证、授权、加密和会话管理。Shiro拥有易于理解的API,您可以快速、轻松地获得任何应用程序——从最小的移动应用程序到最大的网络和企业应用程序。
2.Shiro三个核心组件:
Subject
当前操作用户,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物,仅仅意味着当前跟软件交互的东西,Subject代表了当前用户的安全操作。
SecurityManager
管理所有用户的安全操作,是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realms
充当Shiro与应用安全数据间的”桥梁”或者”连接器”。当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果系统默认的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
权限管理
1.基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源。
2.权限管理(认证授权):对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问
- 身份认证(判断一个用户是否为合法用户的处理过程。如系统通过核对用户输入的用户名和口令与系统中存储的该用户的用户名和口令是否一致来判断用户身份是否正确)
- 授权(访问控制,主体进行身份认证后需要分配权限方可访问系统资源)
简介
- Authentication(认证)、Authorization(授权)、Session Management(会话管理)、Cryptography(加密)被 Shiro 框架的开发团队称之为应用安全的四大基石。
- Authentication(认证):用户身份识别(用户登录)
- Authorization(授权):访问控制
- Session Management(会话管理):特定于用户的会话管理
- Cryptography(加密):对数据源使用加密算法加密
2.核心架构
Subject:
主体,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序
Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权
SecurityManager
- 安全管理器,对全部的subject进行安全管理
- shiro的核心,负责对所有的subject进行安全管理
- 通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等
- SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口
Authenticator
- 认证器,对用户身份进行认证
- Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可自定义认证器
Authorizer
- 授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限
Realm
- 领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,如用户身份数据在数据库那么realm就需要从数据库获取用户身份信息
- realmz不止从数据源取数据,还包括认证授权校验等。
SessionManager
- 会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。
SessionDAO
- 会话dao,是对session会话操作的一套接口,如将session存储到数据库。
CacheManager
- 缓存管理,将用户权限数据存储在缓存,提高性能。
Cryptography
- 密码管理,shiro提供了一套加密/解密的组件,方便开发(MD5)。
认证
1.shiro认证中的关键对象:
- Subject(主体):访问系统的用户,主体可以是进行认证的用户、程序等
- Principal(身份信息):主体进行身份认证的标识,标识具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但必须有一个主身份(Primary Principal)
- credential(凭证信息):只有主体知道的安全信息,如密码、证书等。
2.shiro 配置文件(.ini)
- INI文件是一种无固定标准格式的配置文件。它以简单的文字与简单的结构组成,常常使用在Windows操作系统上(后用注册表代替),许多程序也会采用INI文件做为配置文件之用。
- 节 [section]
- 参数 name=value
- 注解 分号(
;
)
1
2
3
4
5
6
7
8
9 >;last modified 1 April 2001 by John Doe
>[owner]
>name=John Doe
>organization=Acme Products
>[database]
>server=192.0.2.42
>port=143
>file="acme payroll.dat"
- shiro.ini文件默认在/WEB-INF/或classpath下,INI配置文件一般适用于用户少且不需要在运行时动态创建的情景下使用(学习中模拟系统权限数据)。
1 | <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core --> |
1 | public class TestAuthenticator { |
1 | /*自定义类*/ |
1 | public class SimpleAccountRealm extends AuthorizingRealm { |
1 | /** |
1 | /** |
自定义Realm认证
1 | package com.zero.shirodemo.realm; |
1 | public class MyRealmTestAuthenticator { |
1 | protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) { |
MD5 Salt
1.MD5讯息摘要演算法(MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位元(16个字元(BYTES))的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家Ronald Linn Rivest设计,于1992年公开,用以取代MD4演算法。将数据(如一段文字)运算变为另一固定长度值,是杂凑算法的基础原理。2004年,证实MD5演算法无法防止碰撞攻击(英语:Collision_attack),因此不适用于安全性认证,如SSL公开金钥认证或是数位签章等用途。
2.盐(Salt),在密码学中,是指在散列之前将散列内容(如密码)的任意固定位置插入特定的字符串。这个在散列中加入字符串的方式称为"加盐"。其作用是让加盐后的散列结果和没有加盐的结果不相同,在不同的应用情景中,这个处理可以增加额外的安全性。
在大部分情况,盐是不需要保密的。盐可以是随机产生的字符串,其插入的位置可以也是随意而定。如果这个散列结果在将来需要进行验证(例如:验证用户输入的密码),则需要将已使用的盐记录下来。通常情况下,当字段经过散列处理(如SHA-1),会生成一段散列值,而散列后的值一般是无法通过特定算法得到原始字段的。但是某些情况,比如一个大型的彩虹表,通过在表中搜索该SHA-1值,很有可能在极短的时间内找到该散列值对应的真实字段内容。
加盐后的散列值,可以极大的降低由于用户数据被盗而带来的密码泄漏风险,即使通过彩虹表寻找到了散列后的数值所对应的原始内容,但是由于经过了加盐,插入的字符串扰乱了真正的密码,使得获得真实密码的概率大大降低。
1 | public class ShiroMD5Demo { |
1 | public class MyMD5RealmTestAuthenticator { |
1 | public class MyMD5Realm extends AuthorizingRealm { |
授权
1.关键对象:
- 主体(Subject):访问应用的用户。
- 资源(Resource):在应用中用户可以访问的URL,如访问页面、查看或编辑数据、访问业务方法等等都是资源。用户只要授权后才能访问。
- 权限(Permission):安全策略中的原子授权单位,规定了主体对资源的操作许可,通过权限可以表示在应用中用户有没有操作某个资源的权力。
2.授权方式
基于角色的访问控制(Role-Based Access Control)是以角色为中心访问控制
1
2
3 if(subject.hasRole("admin")){
/*操作资源*/
}基于资源的访问控制(Resource-Based Access Control)是以资源为中心访问控制
1
2
3
4
5
6
7
8 /*资源实例*/
if(subject.isPermission("user:update:01")){
/*对01用户具有修改权限*/
}
/*资源类型*/
if(subject.isPermission("user:update:*")){
/*对用户具有修改权限*/
}
- 权限字符串:
资源标识符:操作:资源实例标识符
,对哪个资源的哪个实例具有什么操作(:
分割符,*
通配符)
- 用户创建权限
user:create
或user:create:\*
- 用户修改实例001的权限:
user:update:001
- 用户实例001的所有权限:
user:\*:001
Shiro中授权实现:
1.编程式
1 | Subject subject = SecurityUtils.getSubject(); |
2.注解式
1 |
|
3.标签式
1 | <!--JSP/GSP 标签--> |
Thymeleaf官方没有提供Shiro的标签,需要引入第三方实现: thymeleaf-extras-shiro
1 | public class MyRealm extends AuthorizingRealm { |
1 | public class MyRealmTestAuthenticator { |
SpringBoot集成
1.环境搭建
1 | <dependencies> |
1 | server: |
1.SpringMVC+Shiro初次访问URL出现jsessionid 报400 Bad Request错误:
Set to true to disable support for using URL rewriting to track session IDs for clients of this Context. URL rewriting is an optional component of the servlet 2.5 specification but disabling URL rewriting will result in non-compliant behaviour since the specification requires that there must be a way to retain sessions if the client doesn’t allow session cookies. If not specified, the specification compliant default value of false will be used.
- 修改配置文件
1
2 cookie =
true =
- 修改Shiro配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 /**
* 解决shiro的初次访问URL出现jsessionid 报400 Bad Request错误
*/
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionIdUrlRewritingEnabled(false);
return sessionManager;
}
public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(realm);
defaultWebSecurityManager.setSessionManager(sessionManager());
/*
设置cookie管理器
securityManager.setRememberMeManager(rememberMeManager());
*/
return defaultWebSecurityManager;
}
过滤器
Filter Name | Class |
---|---|
anon | AnonymousFilter |
authc | FormAuthenticationFilter |
authcBasic | BasicHttpAuthenticationFilter |
authcBearer | BearerHttpAuthenticationFilter |
invalidRequest | InvalidRequestFilter |
logout | LogoutFilter |
noSessionCreation | NoSessionCreationFilter |
perms | PermissionsAuthorizationFilter |
port | PortFilter |
rest | HttpMethodPermissionFilter |
roles | RolesAuthorizationFilter |
ssl | SslFilter |
user | UserFilter |