1、受权的三要素html
受权有着三个核心元素:权限、角色和用户。java
权限 apache
权限是Apache Shiro安全机制最核心的元素。它在应用程序中明确声明了被容许的行为和表现。一个格式良好好的权限声明能够清晰表达出用户对该资源拥有的权限。 安全
大多数的资源会支持典型的CRUD操做(create,read,update,delete),可是任何操做创建在特定的资源上才是有意义的。所以,权限声明的根本思想就是创建在资源以及操做上。 jsp
而咱们经过权限声明仅仅能了解这个权限能够在应用程序中作些什么,而不能肯定谁拥有此权限。ui
因而,咱们就须要在应用程序中对用户和权限创建关联。 一般的作法就是将权限分配给某个角色,而后将这个角色关联一个或多个用户。 this
权限声明及粒度编码
Shiro权限声明一般是使用以冒号分隔的表达式。就像前文所讲,一个权限表达式能够清晰的指定资源类型,容许的操做,可访问的数据。同时,Shiro权限表达式支持简单的通配符,能够更加灵活的进行权限设置。spa
下面以实例来讲明权限表达式。
设计
可查询用户数据 User:view
可查询或编辑用户数据 User:view,edit
可对用户数据进行全部操做 User:* 或 user
可编辑id为123的用户数据 User:edit:123
角色
Shiro支持两种角色模式:
一、传统角色:一个角色表明着一系列的操做,当须要对某一操做进行受权验证时,只需判断是不是该角色便可。这种角色权限相对简单、模糊,不利于扩展。
二、权限角色:一个角色拥有一个权限的集合。受权验证时,须要判断当前角色是否拥有该权限。这种角色权限能够对该角色进行详细的权限描述,适合更复杂的权限设计。
下面将详细描述对两种角色模式的受权实现。
2、受权实现
Shiro支持三种方式实现受权过程:
编码实现
注解实现
JSP Taglig实现
一、基于编码的受权实现
1.1基于传统角色受权实现
当须要验证用户是否拥有某个角色(1)时,能够调用Subject 实例的hasRole*(2)方法验证。
Subject currentUser = SecurityUtils.getSubject(); if (currentUser.hasRole("administrator")) { //show the admin button } else { //don't show the button? Grey it out? }
相关验证方法以下:
断言支持
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();
断言的相关方法:
1.2 基于权限角色受权实现
相比传统角色模式,基于权限的角色模式耦合性要更低些,它不会因角色的改变而对源代码进行修改,所以,基于权限的角色模式是更好的访问控制方式。
它的代码实现有如下几种实现方式:
一、基于权限对象的实现
建立org.apache.shiro.authz.Permission的实例(1),将该实例对象做为参数传递给Subject.isPermitted()进行验证(2)。
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 currentUser = SecurityUtils.getSubject(); if (currentUser.isPermitted("printer(资源类型):print(操做):laserjet4400n(资源ID)")) { //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: currentUser.checkPermission("account:open"); openBankAccount();
断言实现的相关方法
二、基于注解的受权实现
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 ... }
@ 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 ... }
@RequiresRoles
当前用户需拥有制定角色
@ RequiresUser
当前用户需为已认证用户或已记住用户
三、基于JSP TAG的受权实现
Shiro提供了一套JSP标签库来实现页面级的受权控制。
在使用Shiro标签库前,首先须要在JSP引入shiro标签:
<%@ 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>
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>
notAuthenticated标签
未认证经过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。
<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?
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>
hasAnyRole标签
验证当前用户是否属于如下任意一个角色。
<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>
lacksPermission标签
与hasPermission标签逻辑相反,当前用户没有制定权限时,验证经过
<shiro:hasPermission name="user:create"> <a href="createUser.jsp">Create a new User</a> </shiro:hasPermission>
3、Shiro受权的内部处理机制
一、在应用程序中调用受权验证方法(Subject的isPermitted*或hasRole*等)
二、Sbuject的实例一般是DelegatingSubject类(或子类)的实例对象,在认证开始时,会委托应用程序设置的securityManager实例调用相应的isPermitted*或hasRole*方法。
三、接下来SecurityManager会委托内置的Authorizer的实例(默认是ModularRealmAuthorizer 类的实例,相似认证明例,它一样支持一个或多个Realm实例认证)调用相应的受权方法。
四、每个Realm将检查是否实现了相同的 Authorizer 接口。而后,将调用Reaml本身的相应的受权验证方法。
当使用多个Realm时,不一样于认证策略处理方式,受权处理过程当中:
一、当调用Realm出现异常时,将当即抛出异常,结束受权验证。
二、只要有一个Realm验证成功,那么将认为受权成功,当即返回,结束认证。