Authorization(授权)
授权,又称作为访问控制,是对资源的访问管理的过程。换句话说,控制谁有权限在应用程序中做什么。 授权检查的例子是:该用户是否被允许访问这个网页,编辑此数据,查看此按钮,或打印到这台打印机?这些都是 决定哪些是用户能够访问的。
1.shiro实现授权的方式:
1. 编写代码——你可以在你的 Java 代码中用像 if 和 else 块的结构执行授权检查。
1.**基于角色授权
a. 角色检查*
所谓角色检查就是,检查当前subject是否具有该角色,从而决定是否能执行相关操作
/*****subject提供这些方法供我们检查当前subject所拥有的角色********/
hasRole(String roleName) 返回 true 如果 Subject 被分配了指定的角色,否则返回 false。
hasRole(List<String> roleNames) 返回 true 如果 Subject 被分配了所有指定的角色,否则返回 false。
hasAllRoles(Collection<String> roleNames) 返回一个与方法参数中目录一致的 hasRole 结果的数组。有性能的提高如果许多角 色需要执行检查(例如,当自定义一个复杂的视图)。
/**********例如***************/
Subject currentUser = SecurityUtils.getSubject();
if(currentUser.hasRole("administrator")) {
//show the admin button
} else {
//don't show the button? Grey it out?
}
b. 角色断言***
所谓角色断言就是使用布尔值在执行需要权限的行为前来判断 Subject 是否拥有一个角色,如果它们有预期的角色,断言将悄悄 地执行,并且逻辑将如预期般继续,如果 Subject 没有预期的角色,AuthorizationException 将会被抛出
/*****subject提供这些方法供我们检查当前subject所拥有的角色********/
checkRole(String roleName) 安静地返回,如果 Subject 被分配了指定的角色,不然的话就抛出 AuthorizationException。
checkRoles(Collection<String> roleNames) 安静地返回,如果 Subject 被分配了所有的指定的角色,不然的话就抛出 AuthorizationException。
checkRoles(String… roleNames) 与上面的 checkRoles 方法的效果相同,但允许 Java5 的 var-args 类型的参数。
/**********例如***************/
Subject currentUser = SecurityUtils.getSubject();
//guarantee that the current user is a bank teller and
//therefore allowed to open the account:
currentUser.checkRole("bankTeller");
openBankAccount();
2 基于权限授权
a. 权限检查*
所谓权限检查就是,看一个 Subject 是否被允许做某事,检查权限主要有 两个方式——基于对象的权限实例或代表权限的字符串.
第一,基于对象的权限检查
执行权限检查的一个可行方法是实例化 org.apache.shiro.authz.Permission 接口的一个 实例,并把它传递给接收权限 实例的*isPermitted 方法。 例如,请考虑以下情况:在办公室有一台打印机,具有唯一标识符 laserjet4400n。我们的软件需要检查当前用户是 否被允许在该打印机上打印文档在我们允许他们按下“打印”按钮之前。上述情况的权限检查可以明确地像这样表达:
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")) {
//show the Print button
} else {
//don't show the button? Grey it out?
}
这个特别的例子显示了一个特殊冒号分隔的格式,它由 Shiro 默认的 org.apache.shiro.authz.permission.WildcardPermission 实现来定义,其中大多数人会找到适合自己的格式。 也就是说,上面的代码块(大部分)是下面代码的简化
/*****subject提供这些方法供我们检查当前subject所拥有的权限********/
isPermitted(Permission p) 返回 true 如果该 Subject 被允许执行某动作或访问被权限实例指定的资源集 合,否则返回 false。
isPermitted(List<Permission> perms) 返回一个与方法参数中目录一致的 isPermitted 结果的数组。有性能的提高如 果需要执行许多检查(例如,当自定义一个复杂的视图)。
isPermittedAll(Collection<Permission> perms) 返回 true 如果该 Subject 被允许所有指定的权限,否则返回 false
b. 权限断言*
相同道理
/*****subject提供这些方法供我们检查当前subject所拥有的权限********/
checkPermission(Permission p) 安静地返回,如果 Subject 被允许执行某 动作或访问被特定的权限实例指定的资 源,不然的话就抛出 AuthorizationException 异常。
checkPermission(String perm) 安静地返回,如果 Subject 被允许执行某 动作或访问被特定的字符串权限指定的 资源,不然的话就抛出 AuthorizationException 异常。
checkPermissions(Collection<Permission> perms) 安静地返回,如果 Subject 被允许所有的 权限,不然的话就抛出 AuthorizationException 异常。
checkPermissions(String… perms) 和上面的 checkPermissions 方法效果相 同,但是使用的是基于字符串的权限
2. JDK 的注解——你可以添加授权注解给你的 Java 方法。
再启动shiro的jdk注解之前,要开启应用程序的aop支持
/**
* shiro AOP 支持
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(getSecurityManager(credentialsMatcher()));
return authorizationAttributeSourceAdvisor;
}
@RequiresAuthentication
//RequiresAuthentication 注解要求当前 Subject 已经在当前的 session 中被验证通过才能被注解的类/实例/方法访问或 调用。
@RequiresAuthentication
public void updateAccount(Account userAccount) {
//this method will only be invoked by a
//Subject that is guaranteed authenticated
…
}
//这通常等同于接下来的基于 Subject 的逻辑:
public void updateAccount(Account userAccount) {
if (!SecurityUtils.getSubject().isAuthenticated()) {
throw new AuthorizationException(...);
}
//Subject is guaranteed authenticated here
…
}
@RequiresGuest
//RequiresGuest 注解要求当前的 Subject 是一个"guest",也就是说,他们必须是在之前的 session 中没有被验证或记住 才能被注解的类/实例/方法访问或调用。
@RequiresGuest
public void signUp(User newUser) {
//this method will only be invoked by a
//Subject that is unknown/anonymous
… }
//这通常等同于接下来的基于 Subject 的逻辑:
public void signUp(User newUser) {
Subject currentUser = SecurityUtils.getSubject();
PrincipalCollection principals = currentUser.getPrincipals();
if (principals != null && !principals.isEmpty()) {
//known identity - not a guest: throw new AuthorizationException(...);
}
//Subject is guaranteed to be a 'guest' here … }
@RequiresPermissions
//RequiresPermissions 注解要求当前的 Subject 被允许一个或多个权限,以便执行注解的方法。
@RequiresPermissions("account:create")
public void createAccount(Account account) {
//this method will only be invoked by a Subject
//that is permitted to create an account
… }
//这通常等同于接下来的基于 Subject 的逻辑:
public void createAccount(Account account) {
Subject currentUser = SecurityUtils.getSubject();
if (!subject.isPermitted("account:create")) {
throw new AuthorizationException(...);
}
//Subject is guaranteed to be permitted here
… }
@RequiresRoles
//RequiresRoles 注解要求当前的 Subject 拥有所有指定的角色。如果他们没有,则该方法将不会被执行,而且 AuthorizationException 异常将会被抛出。
@RequiresRoles("administrator")
public void deleteUser(User user) {
//this method will only be invoked by an administrator
… }
//这通常等同于接下来的基于 Subject 的逻辑:
public void deleteUser(User user) {
Subject currentUser = SecurityUtils.getSubject();
if (!subject.hasRole("administrator")) {
throw new AuthorizationException(...);
}
//Subject is guaranteed to be an 'administrator' here
… }
@RequiresUser
//RequiresUser 注解需要当前的 Subject 是一个应用程序用户才能被注解的类/实例/方法访问或调用。一个“应用程序 用户”被定义为一个拥有已知身份,或在当前 session 中由于通过验证被确认,或者在之前 session 中的'RememberMe' 服务被记住。
@RequiresUser
public void updateAccount(Account account) {
//this method will only be invoked by a 'user'
//i.e. a Subject with a known identity
… }
//这通常等同于接下来的基于 Subject 的逻辑:
public void updateAccount(Account account) {
Subject currentUser = SecurityUtils.getSubject();
PrincipalCollection principals = currentUser.getPrincipals();
if (principals == null || principals.isEmpty()) {
//no identity - they're anonymous, not allowed: throw new AuthorizationException(...); } //Subject is guaranteed to have a known identity here … }
3. JSP/GSP 标签库——你可以控制基于角色和权限的 JSP 或者 GSP 页面输出。
Shiro 提供了一个用于控制 JSP/GSP 页面输出的基于 Subject 状态的标签库。这些包含在 Web 章节的 JSP/GSP 标签库 部分。
<!--首先一定要引入标签-->
<!--jsp-->
<%@ taglib prefix=”shiro” uri=”http://shiro.apache.org/tags” %>
<!--html-->
<html lang="en" xmlns:shiro="http://www.w3.org/1999/xhtml">
<!-- authenticated 用户已经经过身份验证,但不是记住我登录的 -->
<shiro:authenticated>
<shiro:principal />已经经过身份验证<br><br>
</shiro:authenticated>
<!-- 用户没有进行身份验证,记住我自动登录的属于没有进行身份验证 -->
<shiro:notAuthenticated>
用户没有进行身份验证,记住我自动登录的属于没有进行身份验证<br><br>
</shiro:notAuthenticated>
<!-- guest :用户没有验证时显示相应信息 ,如登录等相关信息-->
<shiro:guest>
<a href="login.jsp">登录</a><br><br>
</shiro:guest>
<!-- 当前用户有任意一个角色将会显示body体中的内容 -->
<shiro:hasAnyRoles name="admin,user,manager">
<shiro:principal></shiro:principal>拥有admin/user/manager中的角色<br><br>
</shiro:hasAnyRoles>
<!-- 当前用户有相应的权限,将显示body体中的信息 -->
<shiro:hasPermission name="customer:delete">
<shiro:principal />拥有customer:delete权限<br><br>
</shiro:hasPermission>
<!-- 当前用户没有相应的权限,将显示body体中的信息 -->
<shiro:lacksPermission name="customer:delete">
没有权限customer:delete<br><br>
</shiro:lacksPermission>
<!-- 当前用户没有相应的角色,将显示body中的信息 -->
<shiro:lacksRole name="manager">
<shiro:principal></shiro:principal>没有manager角色<br><br>
</shiro:lacksRole>
<!-- user: 用户已经经过认证/记住我登录后 显示相应的信息 -->
<shiro:user>
<a href="logout">登出</a><br><br>
</shiro:user>
<!-- 当前用户是否拥有该角色,有就显示相关信息 -->
<shiro:hasRole name="admin">
<a href="admin.jsp">Admin Page</a><br><br>
</shiro:hasRole>
---------------------