2.Apache Shiro核心类、接口基本解析

目录


Shiro专栏目录(点击进入…)



Subject(主题)

Subject就像呈现的视图。所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者

Subject currentUser = SecurityUtils.getSubject();  //获取当前执行(登录)的用户
Session session = currentUser.getSession();  //获取session会话
session.setAttribute( "someKey", "aValue" );

通过SecurityUtils.getSubject()获取Subject实例
独立应用程序中的调用可能会Subject在特定于应用程序的位置中返回基于用户数据的,而在服务器环境(例如Web应用程序)中,它会获取Subject与当前线程或传入请求相关联的基于用户数据的


Subject常用方法

(1)登录

方法描述
Object getPrincipal()返回应用程序范围内的唯一标识主体。
如果主题是匿名的,尚无任何关联的帐户数据(尚未登录),则返回null
PrincipalCollection getPrincipals()返回此主题(Subject)的主体(principals)(标识属性)。
如果主题是匿名的,因为它还没有任何关联的帐户数据(尚未登录),返回null
Session getSession()返回与此主题关联的Session
Session getSession(boolean create)返回与此主题关联的Session。
boolean参数确定是否应创建新会话(如果没有现有会话)
boolean isRemembered()Subject是否具有身份(不是匿名),并且principals在上一个会话期间通过成功的身份验证记住该身份
void login(AuthenticationToken token)为此主题(Subject)/用户执行登录尝试
void logout()注销此主题,并使所有关联实体(Session和授权数据)无效和/或将其删除
boolean isAuthenticated()是否登录成功。成功true

(2)角色

方法描述
boolean hasAllRoles(Collection<String>)此主题(Subject)是否具有指定的所有角色;全有返回true,一个不满足返回false
boolean hasRole(String roleIdentifier)此Subject是否具有指定角色
boolean[] hasRoles(List<String>)检查此Subject是否具有指定的角色,并返回一个布尔数组,指示拥有哪些角色

(3)权限

方法描述
boolean[] isPermitted(List<Permission>)检查此主体(Subject)是否暗含给定的权限,并返回一个布尔数组,指示暗含了哪些权限
boolean isPermitted(Permission)是否拥有指定权限
boolean[] isPermitted(String…)检查此Subject是否暗含给定的权限字符串,并返回一个布尔数组,指示暗含了哪些权限
boolean isPermitted(String permission)是否允许此Subject执行操作或访问,指定的权限字符串汇总的资源
boolean isPermittedAll(Collection<Permission>)如果此Subject暗含所有指定的权限,返回true
boolean isPermittedAll(String…)如果此Subject隐含所有指定的权限字符串,返回true

常见异常(登录)

AuthenticationException异常是Shiro在登录认证过程中、认证失败需要抛出的异常。包含以下子类


(1)账号异常(AccountException)

由于执行身份验证尝试的帐户存在问题而引发的异常

异常描述
ConcurrentAccessException并发访问异常(多个用户同时登录时抛出)
UnknownAccountException未知的账号
ExcessiveAttemptsException认证次数超过限制
DisabledAccountException禁用的账号
LockedAccountException账号被锁定
pportedTokenException使用了不支持的Token

(2)凭证异常(CredentialsException)

由于身份验证过程中为帐户提交的凭据有问题而引发异常

异常描述
IncorrectCredentialsException不正确的凭证
ExpiredCredentialsException凭证过期

(3)授权异常(AuthorizationException)

授权(访问控制检查)过程中出现问题,则抛出异常

异常描述
UnauthorizedException抛出以指示请求的操作或对请求的资源的访问是不允许的
UnanthenticatedException当尚未完成认证时,尝试执行授权操作时引发异常

Session(会话)

通过Subject.getSession获取实例,提供了常规HttpSession所使用的大部分功能,但具有一些额外的优点和一个很大的不同:不需要HTTP环境
①部署在Web应用程序内部,则默认情况下Session将HttpSession基于该应用程序
②部署在非Web环境中,Shiro将默认自动使用其企业会话管理

意味着无论部署环境如何,都可以在任何层的应用程序中使用相同的API。这就打开了一个全新的应用程序世界,因为不需要强制要求使用会话的任何应用程序使用HttpSession或EJB状态会话Bean。而且,任何客户端技术现在都可以共享会话数据


ShiroFilterFactoryBean过滤器配置

注意:在使用Shiro框架时,ShiroFilterFactoryBean属性filterChainDefinitions配置过滤器遇到了数量限制问题。当过滤器规则超过12个之后,出现Shiro无法拦截非权限请求的现象

目前解决方法:控制过滤规则数量在12个之内

配置描述
securityManager必须。引入安全管理器
loginUrl没有登录的用户请求需要登录的页面时自动跳转到登录页面,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的“/login.jsp”页面
successUrl登录成功默认跳转页面,可以不配置,不配置则跳转至“/”。如果登陆前点击的一个需要登录的页面,则在登录自动跳转到那个需要登录的页面。
unauthorizedUrl账户权限验证失败跳转的地址
filterChainDefinitions账户权限不够跳转的地址

上面和配置的.ini文件非常相似,其中主要就是配置资源的的拦截。Shiro提供了很多默认的过滤器,比如什么验证,授权等


(1)认证过滤器

注意:定义规则是有顺序的,从上到下,拦截范围必须是从小到大的。调用是上至下

认证过滤器描述
anon匿名过滤器,没有参数。
允许未登录访问,一般用于配置登录页面和静态CSS等资源。/css/** = anon
authc基于表单的过滤器,没有参数。表示需要认证(登录)才能使用
比如:若用户没有登录就会跳转到loginUrl的地址,其拦截的请求必须是通过登录验证的,即Subject.isAuthenticated() == true的账户才能访问。/admins/user/** = authc
logout退出过滤器。Shiro提供了一个退出的功能,配置了/logout = logout,Shiro就会生成一个虚拟的映射路径,当用户访问了这个路径,Shiro会自动清空缓存并跳转到loginUrl页面
user用户过滤器。表示必须存在用户,当登入操作时不做检查
和authc过滤器很类似,都是账户为登录的进行拦截并跳转到loginUrl地址;不同之处在于authc允许账户必须是通过Subject.siAuthenticated() ==true的;而user不仅允许登录账户访问,通过rememberMe登录的用户也能访问
authcBasic/admins/user/**=authcBasic 没有参数,表示httpBasic认证

(2)授权过滤器

授权过滤器描述
roles[角色]参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割
例如:/admins/user/**=roles[“admin,guest”],登录用户同时具有后面的所有角色才能通过认证,相当于hasAllRoles()。
perms[权限]参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割
例如:/admins/user/**=perms[“user:add:,user:modify:”],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()
rest风格过滤器,自动根据请求方法构建权限字符串。
例如 :/admins/user/=rest[user]
根据请求的方法,相当于/admins/user/
=perms[user:method] 其中method为post,get,delete等
port/admins/user/**=port[8081]
当请求的url的端口不是8081是跳转到 schemal://serverName:8081?queryString
其中:
schmal schmal 是协议http或https等
serverName 是访问的host,8081是url配置里port的端口
queryString 是访问的url里的?后面的参数
ssl/admins/user/**=ssl 没有参数,表示安全的url请求,协议为https

控制器收集用户信息(UsernamePasswordToken)

控制器:UsernamePasswordToken
领域:AuthenticationToken(顶层接口)
AuthenticationToken用于收集用户提交的身份(用户名)及凭据(密码)

Shiro会调用CredentialsMatcher对象的doCredentialsMatch(),对AuthenticationInfo对象(登录校验)和AuthenticationToken(权限校验)进行匹配。匹配成功则表示主体(Subject)认证成功,否则表示认证失败

Shiro仅提供了一个可以直接使用的UsernamePasswordToken,用于实现基于用户名/密码主体(Subject)身份认证
UsernamePasswordToken实现了RememberMeAuthenticationToken和HostAuthenticationToken,可以实现“记住我”及“主机验证”的支持


自定义控制器

一般情况下UsernamePasswordToken已经可以满足需求。当遇到需要声明自己的Token类时,可以根据需求来实现下面接口

控制器描述
①AuthenticationToken收集用户提交的身份(用户名)及凭据(密码)
②HostAuthenticationToken保留身份验证尝试源自的主机信息
③RememberMeAuthenticationTokenAuthenticationToken指示用户身份跨会话记住。

(1)如果不需要“记住我”,也不需要“主机验证”,则可以实现AuthenticationToken
(2)如果需要“记住我”,则可以实现RememberMeAuthenticationToken
(3)如果需要“主机验证”功能,则可以实现HostAuthenticationToken
(4)如果需要“记住我”,且需要“主机验证”,则可以像UsernamePasswordToken一样,同时实现RememberMeAuthenticationToken和HostAuthenticationToken
(5)如果需要其他自定义功能,则需要自己实现

注意:当为相应用户创建新会话时,该用户的身份将被记住,但不会被视为已通过身份验证


领域中身份验证(SimpleAuthenticationInfo类)

public class SimpleAuthenticationInfo
implements MergableAuthenticationInfo, SaltedAuthenticationInfo {}

MergableAuthenticationInfo、SaltedAuthenticationInfo接口的简单实现。用于保存主题(Subject)和凭证

顶层接口AuthenticationInfo。SimpleAuthenticationInfo提供了多个构造方法,但是一般密码是经过加密的;Shiro会自动根据token中的用户名和密码与从数据库中查询到的数据进行匹配,如果匹配成功就登录成功,否则就抛出异常


(1)使用方式一

SimpleAuthenticationInfo(PrincipalCollection principals,Object credentials)
SimpleAuthenticationInfo(PrincipalCollection principals
                                      ,Object hashedCredentials
                                      ,ByteSource credentialsSalt)

用于接收帐户的标识主体,验证主体的哈希凭证以及哈希凭证时使用的盐


构造参数

参数描述
principals帐户的识别主题,身份,主体的唯一标识(用户名、自定义Realm名)
比如:用户名、邮箱等,如果将用户名和密码传给了Token对象,那么在Token对象中就能getPrincipal获取这个标识
credentials验证主题的证明、凭据(密码、数字证书、指纹)。
在Shiro等安全框架中,类似于密码这种数据一般都是经过加密处理
credentialsSalt对hashedCredentials进行哈希处理时使用的盐(Salt)

PrincipalCollection

通过PrincipalCollection的实现类SimplePrincipalCollection(Object principal, String realmName)创建

参数描述
principal标识。用户名
realmName凭证。密码
PrincipalCollection principalCollection = new SimplePrincipalCollection(username, realm);

注意:在创建SimplePrincipalCollection实例的时候传入的第一个参数,判断是否是一个对象,是或者不是对象,最终都会加入到SimplePrincipalCollection实例中,可以发现SimpleAuthenticationInfo的第一个参数既可以是user对象也可以是username

在这里插入图片描述

(2)使用方式二

SimpleAuthenticationInfo(Object principal,Object credentials,String realmName)
SimpleAuthenticationInfo(Object principal,Object hashedCredentials,ByteSource credentialsSalt,String realmName)

构造参数

参数描述
principal指定领域(Ream)关联的“主要”主题。传入User类的user对象
注意:此参数可以通过subject.getPrincipal()方法获取(获取当前记录的用户),从这个用户对象进而再获取一系列的所需要的属性
credentials验证主体的凭据。
传入的是从数据库中获取到的password,然后再与token中的password进行对比,匹配上了就通过,匹配不上就报异常
credentialsSalt哈希hashedCredentials时使用的盐(Salt)。
用于加密密码对比。 若不需要,则可以设置为空“”,防止密码被解密破解
realmName获取主题(Subject)和凭证()的领域。当前realm的名字

采用帐户的单个“主要”主体及其对应的凭据(与指定的领域相关联)
构造函数采用帐户的单个“主要”委托人,其对应的哈希凭证,用于哈希凭证的盐以及与委托人相关联的领域的名称
在这里插入图片描述
这是一个方便的构造函数,使用PrincipalCollection基于principal和realmName参数构造一个


领域中用户授权(SimpleAuthorizationInfo类)

AuthorizationInfo接口的简单实现。将角色和权限存储为内部属性

public class SimpleAuthorizationInfo
implements AuthorizationInfo {}

顶层接口:AuthorizationInfo


构造方法

构造方法描述
SimpleAuthorizationInfo()默认无参构造
SimpleAuthorizationInfo(Set<String> roles)创建具有指定角色且没有权限的新实例

成员方法

成员方法描述
void setObjectPermissions(Set<Permission>)设置直接分配给帐户的基于对象的权限
void setRoles(Set<String> roles)设置分配给该帐户的角色
void setStringPermissions(Set<String>)设置直接分配给该帐户的基于字符串的权限
Set<Permission> getObjectPermissions()返回Permission分配给相应Subject的所有类型安全的
Set<String> getRoles()返回分配给相应主题的所有角色的名称
Set<String> getStringPermissions()返回分配给相应主题的所有基于字符串的权限

下面add方法返回值都为void

成员方法描述
addObjectPermission(Permission)向与该帐户直接关联的用户添加(分配)权限
addObjectPermissions(Collection<Permission>)向与该帐户直接关联的权限添加(分配)多个权限
addRole(String role)向与该帐户关联的角色添加(分配)角色
addRoles(Collection<String> roles)向与该帐户关联的角色添加(分配)多个角色
addStringPermission(String permission)向与该帐户直接关联的用户添加(分配)权限
addStringPermissions(Collection<String>)向与该帐户直接关联的权限添加(分配)多个权限

Permission(了解)

权限表示执行操作或访问资源的能力。权限是系统安全策略中最精细或最基本的单元,也是构建细粒度安全模型的基石

public abstract class Permission
implements Guard, java.io.Serializable {}

Permission只有一个implies()方法

方法描述
boolean implies(Permission p)实现此方法,返回值为true,意味着可访问所有资源(超管)
Permission有三个实现类AllPermission、DomainPermission、WildcardPermission

(1)AllPermission实现了Permission

public class AllPermission
implements Permission, Serializable {}

AllPermission实例总是意味着任何其他许可;也就是说,其implies()始终返回true。此类的实例通常仅分配给“root”或“administrator”用户或角色


构造方法:AllPermission(Permission p)

构造方法描述
boolean implies(Permission p)始终返回true。表示任何被授予此权限的Subject都可以执行任何操作

(2)DomainPermission继承了WildcardPermission

public class DomainPermission
extends WildcardPermission {}

(3)WildcardPermission实现了Permission

public class WildcardPermission
implements Permission, Serializable {}

WildcardPermission是一种非常灵活的权限构造,支持多级权限匹配

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SLF4J: No SLF4J providers were found. SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details. Exception in thread "main" org.apache.shiro.config.ConfigurationException: Unable to instantiate class [org.apache.shiro.web.mgt.DefaultWebSecurityManager] for object named 'securityManager'. Please ensure you've specified the fully qualified class name correctly. at org.apache.shiro.config.ReflectionBuilder.createNewInstance(ReflectionBuilder.java:309) at org.apache.shiro.config.ReflectionBuilder$InstantiationStatement.doExecute(ReflectionBuilder.java:927) at org.apache.shiro.config.ReflectionBuilder$Statement.execute(ReflectionBuilder.java:887) at org.apache.shiro.config.ReflectionBuilder$BeanConfigurationProcessor.execute(ReflectionBuilder.java:765) at org.apache.shiro.config.ReflectionBuilder.buildObjects(ReflectionBuilder.java:260) at org.apache.shiro.config.IniSecurityManagerFactory.buildInstances(IniSecurityManagerFactory.java:167) at org.apache.shiro.config.IniSecurityManagerFactory.createSecurityManager(IniSecurityManagerFactory.java:130) at org.apache.shiro.config.IniSecurityManagerFactory.createSecurityManager(IniSecurityManagerFactory.java:108) at org.apache.shiro.config.IniSecurityManagerFactory.createInstance(IniSecurityManagerFactory.java:94) at org.apache.shiro.config.IniSecurityManagerFactory.createInstance(IniSecurityManagerFactory.java:46) at org.apache.shiro.config.IniFactorySupport.createInstance(IniFactorySupport.java:123) at org.apache.shiro.util.AbstractFactory.getInstance(AbstractFactory.java:47) at com.xiu.Quickstart.main(Quickstart.java:26) Caused by: org.apache.shiro.util.UnknownClassException: Unable to load class named [org.apache.shiro.web.mgt.DefaultWebSecurityManager] from the thread context, current, or system/application ClassLoaders. All heuristics have been exhausted. Class could not be found. at org.apache.shiro.util.ClassUtils.forName(ClassUtils.java:152) at org.apache.shiro.util.ClassUtils.newInstance(ClassUtils.java:168) at org.apache.shiro.config.ReflectionBuilder.createNewInstance(ReflectionBuilder.java:302) ... 12 more
06-10
这个异常是因为 Shiro 框架没有找到 SLF4J(Simple Logging Facade for Java)的实现,导致默认使用了 NOP(No-Operation)日志记录器实现。 可以通过以下几个步骤解决这个异常: 1. 确保在应用程序的 classpath 下存在 SLF4J 的实现,比如 Logback、Log4j 等。 2. 确认应用程序中已经正确引入了 SLF4J 的依赖,比如以下 Maven 依赖: ``` <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> ``` 3. 确认 SLF4J 的配置文件是否正确,比如 logback.xml 或者 log4j.properties 等。 如果以上步骤都没有解决问题,可以尝试修改 Shiro 的日志记录器实现,比如使用 Logback 作为日志记录器实现: ``` # 修改 Shiro 的日志记录器实现为 Logback log4j.logger.org.apache.shiro=INFO, stdout log4j.logger.org.apache.shiro.util.ThreadContext=INFO, stdout log4j.logger.org.apache.shiro.realm=INFO, stdout log4j.logger.org.apache.shiro.web=INFO, stdout log4j.logger.org.apache.shiro.cache=INFO, stdout log4j.logger.org.apache.shiro.session=INFO, stdout # Logback 配置文件,可以将日志输出到控制台 <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="org.apache.shiro" level="INFO"/> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> </configuration> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值