这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战
1.简介
- Apache Shiro 是Java的一个安全(权限)框架;
- Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境;
- 主要功能:认证(Authentication)、授权(Authorization)、加密、回话管理、与Web集成、缓存等;
Shiro 架构
- Subject:应用代码直接交互的对象是Subject,也就是说Shiro的对外API 核心就是Subject。Subject 代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;与Subject 的所有交互都会委托给SecurityManager;Subject 其实是一个门面,SecurityManager才是实际的执行者;
- SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且其管理着所有Subject;可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC中DispatcherServlet的角色
- Realm:Shiro从Realm 获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm 得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm 看成DataSource
2.与Spring整合开发
2.1 Shiro认证
2.1.1 配置文件
web.xml
1 | xml复制代码<!-- Shiro 过滤器定义 --> |
applicationContext.xml
1 | xml复制代码 <!-- 1.安全管理器SecurityManager --> |
MyRealm.java
1 | java复制代码public class MyRealm extends AuthorizingRealm{ |
2.1.2 Shiro中默认的过滤器
过滤器类 | 过滤器名称 | 例子 |
---|---|---|
anon | 无参,匿名可访问 | /login.jsp=anon |
authc | 无参,需认证(登录)才能访问 | /admin/**=authc |
user | 无参,表示必须存在用户 | |
perms | 可有多个参数,多个时必须加上引号,参数间用逗号分隔。当有多个参数时必须每个参数都通过,相当于isPermitedAll()方法 | /admin/*=perms[user:add] /admin/**=perms[“user:add,user:update”] |
roles | 角色过滤器,判断当前用户是否指定角色。规则同上。相当于hasAllRoles()方法 | /admin/**=roles[“admin,guest”] |
logout | 注销登录时,完成一定的功能:任何现有的session都将会失效,而且任何身份都将失去关联(web程序中,RememberMe cookie也将会被删除) |
2.1.3 URL匹配模式
使用Ant风格模式,Ant路径通配符支持 ?、*、**,通配符匹配不包括目录分隔符 “/“
- ? : 匹配一个字符,如:/admin?,匹配:/admin1;不匹配:/admin123, /admin/
- *:匹配零个或多个字符串或一个路径
- **:匹配路径中的零个或多个路径
2.1.4 URL匹配顺序
第一次匹配优先的方式。所以一般 /* 的路径访问都放在后面。
2.1.5 Shiro加密
Shiro 认证中密码比对:使用AuthorizingRealm中的 credentialsMatcher 进行的密码比对。
1、md5加密(不可逆的)
(1).如何把一个字符串加密为MD5;
(2).替换当前 Realm的credentialsMatcher 属性,直接使用HashedCredentialsMather对象,并设置加密算法。
applicationContext.xml
1 | xml复制代码 <!-- 3.自定义Realm |
这时候服务器会自动将浏览器传来的密码使用 MD5加密,加密1024次。
2、md5盐值加密
applicationContext.xml不变
(1). doGetAuthenticationInfo方法返回值创建SimpleAuthenticationInfo,使用构造器:
SimpleAuthenticationInfo(principal, hashedCredentials, credentialsSalt, realmName);
(2). 使用ByteSource.Util.bytes(username);加密盐值
(3). 盐值需唯一,一般使用随机字符串、user id
(4). 可以使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 计算盐值加密后的值。
1 | java复制代码 /** |
MD5Test.java
1 | java复制代码public class MD5Test { |
2.1.6 多Reaml
为什么使用多 Realm ?
根据不同的登录需求,需要做不同的验证。如:手机号登录、邮箱登录。。。
使用 ModularRealmAuthenticator类,属性Collection realms;注入 Realm集合
SecondRealm.java 同MyRealm类,将验证密码改为 SHA1加密后的值。
applicationContext.xml
1 | xml复制代码 <bean id="secondRealm" class="com.xiaojian.shiro.realms.SecondRealm"> |
认证策略 (AuthenticationStrategy)
AuthenticationStrategy 接口的默认实现:
- FirstSuccessfulStrategy: 还要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息,其他的忽略;
- AtLeastOneSuccessfulStrategy: 只要有一个 Realm 验证成功即可,和 FirstSuccessfulStrategy 不同,将返回所有 Realm 身份验证成功的认证信息;
- AllSuccessfulStrategy: 所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的认证信息,如果有一个失败就失败了。
- ModularRealmAuthenticator 默认是 AtLeastOneSuccessfulStrategy 策略
配置:
1 | xml复制代码<bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator"> |
使用多 Realm 后,可以把 authenticator 配置给 SecurityManager
通常将所有的 Realm 配置给 安全管理器SecurityManager
1 | xml复制代码之后 |
2.2 Shiro 授权
多 Realm 实现授权时,有一个通过,都是授权通过。
1 | xml复制代码Shiro过滤器添加角色拦截 |
MyRealm.java
1 | java复制代码/** |
2.3 Shiro 标签
Shiro 提供了 JSTL 标签用于在 JSP 页面进行权限控制,如根据登录用户显示相应的页面按钮。
标签 | 描述 | 示例 |
---|---|---|
guest | 用户没有身份验证时显示相应信息,即游客信息 | image-20200307234952932 |
user | 用户已经经过认证/记住我登录后显示相应的信息 | image-20200308000528385 |
authenticated | 用户已经身份验证通过,即 Subject.login登录成功,不是记住我登录的 | image-20200308000656696 |
notAuthenticated | 用户未进行身份验证,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。 | image-20200308000937683 |
pincipal | 显示用户身份信息,默认调用 | image-20200308001012588 |
hasRole | 如果当前Subject 有角色将显示body 体内容 | image-20200308001040891 |
hasAnyRoles | 如果当前Subject有任意一个角色(或的关系)将显示body体内容。 | image-20200308001147878 |
lacksRole | 如果当前Subject 没有角色将显示body 体内容 | image-20200308001256323 |
hasPermission | 如果当前Subject 有权限将显示body 体内容 | image-20200308001314089 |
lacksPermission | 如果当前Subject没有权限将显示body体内容 | image-20200308001326991 |
本文转载自: 掘金