3 Apache Shiro 授权

3.1 概述

授权,又称访问控制,即在应用中控制用户可以使用哪些资源(如访问页面、页面操作、数据操作等),覆盖以下几个概念:
(1) 主体(Subject)
即用户,Shiro 中使用 Subject 代表用户。
(2) 角色(Role)
代表权限的集合,可以将权限集合起来一次性赋予用户。
(3) 权限(Permission)
安全策略中的原子授权单位,权限表示操作某个资源的能力。
(4) 资源(Resource)
应用中可以访问或操作的资源、如页面、数据、业务方法等。

角色又分为:
隐式角色
直接通过角色验证用户是否有某资源的操作权限。如果需要取消该权限,需要将用户对应的角色去除,属于粗粒度的权限控制。
显式角色
通过角色绑定的权限集合验证用户是否有某资源的操作权限。如果需要取消该权限,只需要将该权限从角色绑定的权限集合中去除,不需要去除用户的角色,属于细粒度的权限控制。

3.2 授权方式

Shiro 支持三种授权方式:
(1) 编程式
通过写 if/else 授权代码块实现
(2) 注解式
通过在执行的 Java 方法上放置注解 @RequiresRoles("admin") 实现
(3) JSP/GSP 标签
通过在 JSP/GSP 页面添加标签 <shiro:hasRole> 实现

3.3 授权实现

(1) 基于角色的访问控制(隐式角色)
首先,在 ini 配置文件(shiro-role.ini)中配置用户拥有的角色。

[users]
Steve=001,role1,role2
Tony=002,role1

在 ini 配置文件中配置用户角色规则:
用户名=密码,角色1,角色2,…
如果需要在应用中判断用户是否具有相应角色,需要在相应的 Realm 中返回角色信息,Shiro 不负责维护用户和角色的信息,需要应用自己提供,Shiro 只提供相应接口实现验证。

其次,编写测试用例。

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Arrays;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.apache.shiro.util.ThreadContext;
import org.junit.After;
import org.junit.Test;

public class ShiroTest {

    @Test
    public void testHasRole() {
        login("classpath:shiro-role.ini", "Steve", "001");
        assertTrue(subject().hasRole("role1"));
        assertTrue(subject().hasRole("role2"));
        boolean[] result = subject().hasRoles(Arrays.asList("role1", "role2", "role3"));
        assertTrue(result[0]);
        assertTrue(result[1]);
        assertFalse(result[2]);
    }

    private void login(String configFile, String username, String password) {
        // 1.获取SecurityManager工厂,使用ini配置文件初始化SecurityManager
        Factory<SecurityManager> factory = new IniSecurityManagerFactory(configFile);
        // 2.获取SecurityManager实例
        SecurityManager securityManager = factory.getInstance();
        // 3.将SecurityManager实例绑定给SecurityUtils
        SecurityUtils.setSecurityManager(securityManager);
        // 4.通过SecurityUtils获取Subject
        Subject subject = SecurityUtils.getSubject();
        // 5.创建用户名、密码身份验证token
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        // 6.使用用户名、密码身份验证token进行身份认证,即登录
        subject.login(token);
    }

    private Subject subject() {
        return SecurityUtils.getSubject();
    }

    @After
    public void tearDown() {
        // 如果需要同时运行多个test方法,在每个方法退出时需要解除绑定到当前线程的Subject实例,否则会影响接下来的test方法的执行。
        ThreadContext.unbindSubject();
    }

}

Shiro 提供 boolean hasRole(String roleIdentifier)boolean[] hasRoles(List<String> roleIdentifiers) 方法用于判断用户是否拥有某个角色。
Shiro 还提供了 void checkRole(String roleIdentifier) throws AuthorizationExceptionvoid checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException 方法检查用户是否拥有某个角色,与 hasRolehasRoles 方法的不同之处在于:如果检查出用户不具有某种角色,hasRolehasRoles 方法会返回 false,而 checkRolecheckRoles 方法会抛出 UnauthorizedException 异常。
测试用例(上个测试用例中其它方法不变,只需要将 testHasRole 方法替换为 testCheckRole 方法):

@Test(expected = UnauthorizedException.class)
public void testCheckRole() {
    login("classpath:shiro-role.ini", "Steve", "001");
    subject().checkRole("role1");
    subject().checkRoles(Arrays.asList("role1", "role3"));
}

(2) 基于资源的访问控制(显式角色)
首先,在 ini 配置文件(shiro-permission.ini)中配置用户拥有的角色及角色、权限关系。

[users]
Steve=001,role1,role2
Tony=002,role1
[roles]
#对资源user拥有createupdate权限
role1=user:create,user:update
#对资源user拥有createdelete权限
role2=user:create,user:delete

在 ini 配置文件中配置角色、权限关系的规则:
角色=权限1,权限2,…
配合之前介绍的配置用户角色规则:
用户名=密码,角色1,角色2,…
可知,先根据用户名和密码进行身份认证,通过后根据用户名找到角色,再根据角色找到对应的权限集合。

其次,编写测试用例。

@Test
public void testIsPermitted() {
    login("classpath:shiro-permission.ini", "Steve", "001");
    assertTrue(subject().isPermitted("user:create"));
    assertTrue(subject().isPermittedAll("user:update", "user:delete"));
    assertFalse(subject().isPermitted("user:view"));
}

Shiro 提供了 boolean isPermitted(String permission)boolean isPermittedAll(String... permissions) 方法用于判断用户是否拥有某权限。
Shiro 还提供了 void checkPermission(String permission) throws AuthorizationExceptionvoid checkPermissions(String... permissions) throws AuthorizationException 方法检查用户是否拥有某权限,如果检查出用户不拥有目标权限,会抛出 UnauthorizedException 异常。
测试用例:

@Test(expected = UnauthorizedException.class)
public void testCheckPermission() {
    login("classpath:shiro-permission.ini", "Steve", "001");
    subject().checkPermission("user:create");
    subject().checkPermissions("user:update", "user:delete");
    subject().checkPermission("user:view");
}

3.4 字符串通配符权限

规则:资源标识符:操作:对象实例ID,即对哪个资源的哪个实例执行何种操作。其中:

  • “:”用于分隔资源/操作/实例
  • “,”用于分隔多个操作
  • “*”用于表示任意资源、操作或实例

(1) 单个资源的单个权限
java:subject().checkPermissions("system:user:create");
资源 system:usercreate 权限。
(2) 单个资源的多个权限
ini:role41=system:user:update,system:user:delete
java:subject().checkPermissions("system:user:update", "system:user:delete");
资源 system:userupdatedelete 权限。
可以简写为:
ini:role42="system:user:update,delete"
java:subject().checkPermissions("system:user:update,delete");
注意:通过 "system:user:update,delete" 验证 "system:user:update", "system:user:delete" 是没问题的,但是反过来规则不成立。
(3) 单个资源的全部权限

(4) 所有资源的全部权限

(5) 实例级别的权限

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

又言又语

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值