授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。
如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等。
一、授权的三要素
授权有着三个核心元素:权限、角色和用户。
权限
权限是Apache Shiro安全机制最核心的元素。它在应用程序中明确声明了被允许的行为和表现。一个格式良好好的权限声明可以清晰表达出用户对该资源拥有的权限。
大多数的资源会支持典型的CRUD操作(create,read,update,delete),但是任何操作建立在特定的资源上才是有意义的。因此,权限声明的根本思想就是建立在资源以及操作上。
而我们通过权限声明仅仅能了解这个权限可以在应用程序中做些什么,而不能确定谁拥有此权限。
于是,我们就需要在应用程序中对用户和权限建立关联。
通常的做法就是将权限分配给某个角色,然后将这个角色关联一个或多个用户。
权限声明及粒度
Shiro权限声明通常是使用以冒号分隔的表达式。就像前文所讲,一个权限表达式可以清晰的指定资源类型,允许的操作,可访问的数据。同时,Shiro权限表达式支持简单的通配符,可以更加灵活的进行权限设置。
下面以实例来说明权限表达式。
可查询用户数据
User:view
可查询或编辑用户数据
User:view,edit
可对用户数据进行所有操作
User:* 或 user
可编辑id为123的用户数据
User:edit:123
角色
Shiro支持两种角色模式:
1、传统角色:一个角色代表着一系列的操作,当需要对某一操作进行授权验证时,只需判断是否是该角色即可。这种角色权限相对简单、模糊,不利于扩展。
2、权限角色:一个角色拥有一个权限的集合。授权验证时,需要判断当前角色是否拥有该权限。这种角色权限可以对该角色进行详细的权限描述,适合更复杂的权限设计。
下面将详细描述对两种角色模式的授权实现。
二、授权实现
Shiro支持三种方式实现授权过程:
- 编码实现
- 注解实现
- JSP Taglig实现
1、基于编码的授权实现
1.1基于传统角色授权实现
当需要验证用户是否拥有某个角色时,可以调用Subject 实例的hasRole*方法验证。
- Subject currentUser = SecurityUtils.getSubject();
- if (currentUser.hasRole("administrator")) {
- //show the admin button
- } else {
- //don't show the button? Grey it out?
- }
Subject currentUser = SecurityUtils.getSubject(); if (currentUser.hasRole("administrator")) { //show the admin button } else { //don't show the button? Grey it out? }
相关验证方法如下:
Subject方法 | 描述 |
hasRole(String roleName) | 当用户拥有指定角色时,返回true |
hasRoles(List<String> roleNames) | 按照列表顺序返回相应的一个boolean值数组 |
hasAllRoles(Collection<String> roleNames) | 如果用户拥有所有指定角色时,返回true |
断言支持
Shiro还支持以断言的方式进行授权验证。断言成功,不返回任何值,程序继续执行;断言失败时,将抛出异常信息。使用断言,可以使我们的代码更加简洁。
- Subject currentUser = SecurityUtils.getSubject();
- //guarantee that the current user is a bank teller and
- //therefore allowed to open the account:
- currentUser.checkRole("bankTeller");
- openBankAccount();
Subject currentUser = SecurityUtils.getSubject(); //guarantee that the current user is a bank teller and //therefore allowed to open the account: currentUser.checkRole("bankTeller"); openBankAccount();
断言的相关方法:
Subject方法 | 描述 |
checkRole(String roleName) | 断言用户是否拥有指定角色 |
checkRoles(Collection<String> roleNames) | 断言用户是否拥有所有指定角色 |
checkRoles(String... roleNames) | 对上一方法的方法重载 |
1.2 基于权限角色授权实现
相比传统角色模式,基于权限的角色模式耦合性要更低些,它不会因角色的改变而对源代码进行修改,因此,基于权限的角色模式是更好的访问控制方式。
它的代码实现有以下几种实现方式:
1、基于权限对象的实现
创建org.apache.shiro.authz.Permission的实例,将该实例对象作为参数传递给Subject.isPermitted()进行验证。
- Permission printPermission = new PrinterPermission("laserjet4400n", "print");
- Subject currentUser = SecurityUtils.getSubject();
- if (currentUser.isPermitted(printPermission)) {
- //show the Print button
- } else {
- //don't show the button? Grey it out?
- }
- Permission printPermission = new PrinterPermission("laserjet4400n", "print");
- Subject currentUser = SecurityUtils.getSubject();
- if (currentUser.isPermitted(printPermission)) {
- //show the Print button
- } else {
- //don't show the button? Grey it out?
- }
Permission printPermission = new PrinterPermission("laserjet4400n", "print"); Subject currentUser = SecurityUtils.getSubject(); if (currentUser.isPermitted(printPermission)) { //show the Print button } else { //don't show the button? Grey it out? } Permission printPermission = new PrinterPermission("laserjet4400n", "print"); Subject currentUser = SecurityUtils.getSubject(); if (currentUser.isPermitted(printPermission)) { //show the Print button } else { //don't show the button? Grey it out? }
相关方法如下:
Subject方法 | 描述 |
isPermitted(Permission p) | Subject拥有制定权限时,返回treu |
isPermitted(List<Permission> perms) | 返回对应权限的boolean数组 |
isPermittedAll(Collection<Permission> perms) | Subject拥有所有制定权限时,返回true |
2、 基于字符串的实现
相比笨重的基于对象的实现方式,基于字符串的实现便显得更加简洁。
- Subject currentUser = SecurityUtils.getSubject();
- if (currentUser.isPermitted("printer:print:laserjet4400n")) {
- //show the Print button
- } else {
- //don't show the button? Grey it out?
- }
Subject currentUser = SecurityUtils.getSubject(); if (currentUser.isPermitted("printer:print:laserjet4400n")) { //show the Print button } else { //don't show the button? Grey it out? }
使用冒号分隔的权限表达式是org.apache.shiro.authz.permission.WildcardPermission 默认支持的实现方式。
这里分别代表了 资源类型:操作:资源ID
类似基于对象的实现相关方法,基于字符串的实现相关方法:
isPermitted(String perm)、isPermitted(String... perms)、isPermittedAll(String... perms)
基于权限对象的断言实现
- Subject currentUser = SecurityUtils.getSubject();
- //guarantee that the current user is permitted
- //to open a bank account:
- Permission p = new AccountPermission("open");
- currentUser.checkPermission(p);
- openBankAccount();
Subject currentUser = SecurityUtils.getSubject(); //guarantee that the current user is permitted //to open a bank account: Permission p = new AccountPermission("open"); currentUser.checkPermission(p); openBankAccount();
基于字符串的断言实现
- Subject currentUser = SecurityUtils.getSubject();
- //guarantee that the current user is permitted
- //to open a bank account:
- currentUser.checkPermission("account:open");
- openBankAccount();
Subject currentUser = SecurityUtils.getSubject(); //guarantee that the current user is permitted //to open a bank account: currentUser.checkPermission("account:open"); openBankAccount();
断言实现的相关方法
Subject方法 | 说明 |
checkPermission(Permission p) | 断言用户是否拥有制定权限 |
checkPermission(String perm) | 断言用户是否拥有制定权限 |
checkPermissions(Collection<Permission> perms) | 断言用户是否拥有所有指定权限 |
checkPermissions(String... perms) | 断言用户是否拥有所有指定权限 |
2、基于注解的授权实现
Shiro注解支持AspectJ、Spring、Google-Guice等,可根据应用进行不同的配置。
相关的注解:
@ RequiresAuthentication
可以用户类/属性/方法,用于表明当前用户需是经过认证的用户。
- @RequiresAuthentication
- public void updateAccount(Account userAccount) {
- //this method will only be invoked by a
- //Subject that is guaranteed authenticated
- ...
- }
@RequiresAuthentication public void updateAccount(Account userAccount) { //this method will only be invoked by a //Subject that is guaranteed authenticated ... }
@ RequiresGuest
表明该用户需为”guest”用户
@ RequiresPermissions
当前用户需拥有制定权限
- @RequiresPermissions("account:create")
- public void createAccount(Account account) {
- //this method will only be invoked by a Subject
- //that is permitted to create an account
- ...
- }
@RequiresPermissions("account:create") public void createAccount(Account account) { //this method will only be invoked by a Subject //that is permitted to create an account ... }
@RequiresRoles
当前用户需拥有制定角色
@ RequiresUser
当前用户需为已认证用户或已记住用户
3、基于JSP TAG的授权实现
Shiro提供了一套JSP标签库来实现页面级的授权控制。
在使用Shiro标签库前,首先需要在JSP引入shiro标签:
- <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
下面一一介绍Shiro的标签:
guest标签
验证当前用户是否为“访客”,即未认证(包含未记住)的用户
- <shiro:guest>
- Hi there! Please <a href="login.jsp">Login</a> or <a href="signup.jsp">Signup</a> today!
- </shiro:guest>
<shiro:guest> Hi there! Please <a href="login.jsp">Login</a> or <a href="signup.jsp">Signup</a> today! </shiro:guest>
user标签
认证通过或已记住的用户
- <shiro:user>
- Welcome back John! Not John? Click <a href="login.jsp">here<a> to login.
- </shiro:user>
<shiro:user> Welcome back John! Not John? Click <a href="login.jsp">here<a> to login. </shiro:user>
authenticated标签
已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。
- <shiro:authenticated>
- <a href="updateAccount.jsp">Update your contact information</a>.
- </shiro:authenticated>
<shiro:authenticated> <a href="updateAccount.jsp">Update your contact information</a>. </shiro:authenticated>
notAuthenticated标签
未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。
- <shiro:notAuthenticated>
- Please <a href="login.jsp">login</a> in order to update your credit card information.
- </shiro:notAuthenticated>
<shiro:notAuthenticated> Please <a href="login.jsp">login</a> in order to update your credit card information. </shiro:notAuthenticated>
principal 标签
输出当前用户信息,通常为登录帐号信息
- Hello, <shiro:principal/>, how are you today?
Hello, <shiro:principal/>, how are you today?
hasRole标签
验证当前用户是否属于该角色
- <shiro:hasRole name="administrator">
- <a href="admin.jsp">Administer the system</a>
- </shiro:hasRole>
<shiro:hasRole name="administrator"> <a href="admin.jsp">Administer the system</a> </shiro:hasRole>
lacksRole标签
与hasRole标签逻辑相反,当用户不属于该角色时验证通过
- <shiro:lacksRole name="administrator">
- Sorry, you are not allowed to administer the system.
- </shiro:lacksRole>
<shiro:lacksRole name="administrator"> Sorry, you are not allowed to administer the system. </shiro:lacksRole>
hasAnyRole标签
验证当前用户是否属于以下任意一个角色。
- <shiro:hasAnyRoles name="developer, project manager, administrator">
- You are either a developer, project manager, or administrator.
- </shiro:lacksRole>
<shiro:hasAnyRoles name="developer, project manager, administrator"> You are either a developer, project manager, or administrator. </shiro:lacksRole>
hasPermission标签
验证当前用户是否拥有制定权限
- <shiro:hasPermission name="user:create">
- <a href="createUser.jsp">Create a new User</a>
- </shiro:hasPermission>
<shiro:hasPermission name="user:create"> <a href="createUser.jsp">Create a new User</a> </shiro:hasPermission>
lacksPermission标签
与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过
- <shiro:hasPermission name="user:create">
- <a href="createUser.jsp">Create a new User</a>
- </shiro:hasPermission>
<shiro:hasPermission name="user:create"> <a href="createUser.jsp">Create a new User</a> </shiro:hasPermission>
三、Shiro授权的内部处理机制
1、在应用程序中调用授权验证方法(Subject的isPermitted*或hasRole*等)
2、Sbuject的实例通常是DelegatingSubject类(或子类)的实例对象,在认证开始时,会委托应用程序设置的securityManager实例调用相应的isPermitted*或hasRole*方法。
3、接下来SecurityManager会委托内置的Authorizer的实例(默认是ModularRealmAuthorizer 类的实例,类似认证实例,它同样支持一个或多个Realm实例认证)调用相应的授权方法。
4、每一个Realm将检查是否实现了相同的 Authorizer 接口。然后,将调用Reaml自己的相应的授权验证方法。
当使用多个Realm时,不同于认证策略处理方式,授权处理过程中:
1、当调用Realm出现异常时,将立即抛出异常,结束授权验证。
2、只要有一个Realm验证成功,那么将认为授权成功,立即返回,结束认证。
相关推荐
它为开发者提供了一种标准的方式来处理用户身份验证和授权,使得开发者能够轻松地在应用程序中集成安全功能。JAAS的主要目标是提供一个模块化的、可扩展的安全框架,以适应各种安全需求。 首先,我们来理解一下身份...
认证是验证用户身份的过程,在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法。Shiro 提供了多种认证机制,例如用户名/密码认证、Remember Me 认证等。 2. 授权...
用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法。Shiro通过认证器(Authenticator)组件来完成认证过程。 Authorizer负责授权,授权实质上是访问控制的过程,用于决定用户是否有...
Java认证和授权服务(Java Authentication and Authorization Service,简称JAAS)是Java平台提供的一种安全机制,用于处理用户身份验证和权限管理。它为开发者提供了一种标准的方式来集成各种安全策略和认证机制,...
3. **主体(Subject)**:在用户成功登录后,所有关于此用户的安全信息(如 Principals 和 Credentials)都会存储在Subject对象中。 4. **应用程序代码**:这部分代码会使用`Subject`和`CallbackHandler`来启动认证...
1. **收集实体/凭据信息:** 用户需要提交实体信息 (Principals) 和凭据信息 (Credentials) 以验证其身份。 - 示例代码: ```java // 使用最常见的用户名/密码组合场景 UsernamePasswordToken token = new ...
### Shiro 获取登录状态与用户信息 在Java Web开发领域,Apache Shiro 是一个非常流行的权限管理框架。...以上就是关于如何在Shiro框架中获取用户登录状态和用户信息的相关知识点。希望对你有所帮助!
用户需要提供实体信息(Principals)和凭据信息(Credentials)来证明其合法性。最普遍的方式是使用用户名/密码组合。例如,以下 Java 代码展示了如何创建一个 `UsernamePasswordToken` 对象: ```java // 创建 ...
在 Shiro 的认证过程中,用户需要提供实体信息(Principals)和凭据信息(Credentials)。Principals 是用来唯一标识用户的身份,比如用户名、身份证号等;Credentials 则是用来验证这些身份的证据,常见的如密码。...
1. 应用程序根据用户的身份和凭证(principals和credentials)来构造出AuthenticationToken实例,并调用Subject.login的方法进行登录,其会自动委托给Security Manager。 2. Subject实例通常上都是DelegatingSubject...
3. **认证结果**:如果认证成功,LoginModule将创建一个Subject对象,该对象包含了验证过的用户身份信息(Principals)和其他安全相关信息。然后,LoginModule会向控制台报告成功的状态,并返回到JAAS框架。 4. **...
Azure Stack的认证机制包括了OpenID Connect协议,这是一种轻量级身份验证协议,用于在用户和身份提供者之间建立信任关系。例如,用户可以通过admindir.onmicrosoft.com或Fabrikam.com等Azure Stack AD实例进行登录...
Shiro 提供了用户认证、授权、会话管理和加密等核心功能,帮助开发者轻松实现系统的安全性。本次催米技术部的Shiro权限管理培训内容主要涵盖了以下几个方面: 1. **权限管理概述**: 权限管理是系统安全的基础,它...
4. **返回认证信息**:如果认证成功,`Realm` 将返回一个实现了 `AuthenticationInfo` 接口的对象,其中包含用户的主体信息(Subject)、凭据和其他相关信息。Shiro 会使用这些信息来创建一个 `AuthenticationToken`...
Apache Shiro 是一款Java安全框架,它提供了身份认证、授权、加密和会话管理功能,适用于Java SE和Java EE环境,甚至能在分布式集群环境中运行。Shiro因其简单易用而受到青睐,相比于依赖Spring的Spring Security,...
- **备份现有配置**:在进行任何数据库迁移之前,务必备份现有数据库的配置信息,包括登录名和用户权限等。 - **统一命名规则**:确保所有登录名和用户名采用一致的命名规则,方便迁移后的匹配工作。 - **预迁移测试...
4. **主体和权限**:在认证过程中,成功的登录会创建一个或多个主体(principals),代表了验证的用户。这些主体随后与权限关联,定义了用户可以执行的操作。例如,`JAASdemo` 可能会创建一个用户主体,并根据`demo....
Java Authentication and Authorization Service (JAAS) 是Java平台中用于安全性的关键组件,它提供了一种标准框架来实现用户身份验证和授权。在Web应用程序中,JAAS被用来控制对资源的访问,确保只有经过验证的用户...
包含 Principals 和 Credentials 两个信息。我们看下两者的具体含义。 Principals:代表身份。可以是用户名、邮件、手机号码等等,用来标识一个登录主体的身份。 Credentials:代表凭证。常见的有密码,数字证书等等...
### Shiro 入门教程:理解 Java 中的认证过程 #### 概述 Apache Shiro 是一个强大且易用的 Java 安全框架,它执行安全相关的任务,如认证、授权、加密和会话管理。本教程将详细介绍 Shiro 中的认证流程,适合初学...