Shiro授权流程

99 阅读3分钟
1. 授权

授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。

2. 关键对象

授权可简单理解为 who 对 what (which) 进行 How 操作:

  • Who,即主体(Subject),主体需要访问系统中的资源。

  • What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。

  • How,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。

3. 授权流程

4. 授权方式
  • 基于角色的访问控制
    • RBAC基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制

      if(subject.hasRole("admin")){
         //操作什么资源
      }
      
  • 基于资源的访问控制
    • RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制

      if(subject.isPermission("user:update:01")){ //资源实例
        //对01用户进行修改
      }
      if(subject.isPermission("user:update:*")){  //资源类型
        //对01用户进行修改
      }
      
5. 权限字符串

权限字符串的规则是:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用 * 通配符。

例子:

  • 用户创建权限:user:create,或user:create:*
  • 用户修改实例001的权限:user:update:001
  • 用户实例001的所有权限:user:*:001
6. shiro中授权编程实现方式
  • 编程式

    Subject subject = SecurityUtils.getSubject();
    if(subject.hasRole("admin")) {
    	//有权限
    } else {
    	//无权限
    }
    
  • 注解式

    @RequiresRoles("admin")
    public void hello() {
    	//有权限
    }
    
  • 标签式

    JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:
    <shiro:hasRole name="admin">
    	<!— 有权限—>
    </shiro:hasRole>
    注意: Thymeleaf 中使用shiro需要额外集成!
    
7. 开发授权
7.1 realm的实现
public class CustomerRealm extends AuthorizingRealm {
    // 授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String primaryPrincipal = (String) principals.getPrimaryPrincipal();
        System.out.println("primaryPrincipal = " + primaryPrincipal);

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        simpleAuthorizationInfo.addRole("admin");

        simpleAuthorizationInfo.addStringPermission("user:update:*");
        simpleAuthorizationInfo.addStringPermission("product:*:*");


        return simpleAuthorizationInfo;
    }

    // 认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        if("xiaochen".equals(principal)){
            String password = "3c88b338102c1a343bcb88cd3878758e";
            String salt = "Q4F%";
            return new SimpleAuthenticationInfo(principal, password, ByteSource.Util.bytes(salt), this.getName());
        }
        return null;
    }

}
7.2 授权
public class TestAuthenticatorCusttomerRealm {
    public static void main(String[] args) {
        // 创建securityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        // 设置为自定义realm获取认证数据
        CustomerRealm customerRealm = new CustomerRealm();
        // 设置md5加密
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        // 设置散列次数
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        defaultSecurityManager.setRealm(customerRealm);
        // 将安装工具类中设置默认安全管理器
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        // 获取主体对象
        Subject subject = SecurityUtils.getSubject();
        // 创建token令牌
        UsernamePasswordToken token = new UsernamePasswordToken("whw", "123");
        try {
            // 用户登录
            subject.login(token);
            System.out.println("登录成功!");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误!!");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误!!!");
        }
        // 认证通过
        if(subject.isAuthenticated()){
            // 基于角色权限管理
            boolean admin = subject.hasRole("admin");
            System.out.println(admin);

            boolean permitted = subject.isPermitted("product:create:001");
            System.out.println(permitted);
        }

    }
}