5、Shiro实现授权

授权

授权概述

授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、 角色(Role)。

关键对象介绍

  • 主体

    主体,即访问应用的用户,在Shiro中使用Subject代表该用户。用户只有授权后才允许访问相应的资源。

  • 资源

    在应用中用户可以访问的任何东西,比如访问JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。

  • 权限

    安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD式权限控制)打印文档等等。

  • 角色

    角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。

授权流程

相关方法说明:

//判断是否有角色 
subject.hasRole(""); 
//分别判断用户是否具有List中每个内容 
subject.hashRoles(List);
//返回boolean,要求参数中所有角色用户都需要具有
subject.hasAllRoles(Collection); 
//判断是否具有权限.
subject.isPermitted("");

shiro.ini方式实现授权

1、配置shiro.ini

# 配置用户
[users]
zhangsan=123456,role1
lisi=123456,role3

# 配置角色
[roles]
role1=user:view,user:create,user:delete,user:update
role2=user:view
role3=user:view,user:create

权限标识符号规则:资源:操作:实例,中间使用半角:分隔。

user:create:01 :表示对用户资源的01实例进行create操作。

user:create:表示对用户资源进行create操作,相当于user:create:*,对所有用户资源实例进行create操作。

user:*:01 :表示对用户资源实例01进行所有操作。

2、测试用户是否有当前角色和权限

package com.coydone.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
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 java.util.ArrayList;
import java.util.List;

public class AuthUserTeat {

    public static void main(String[] args) {
        //1、接收用户名和密码
        String username = "zhangsan";
        String password = "123456";

        //2、把用户名和密码封装
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);

        //3、创建安全管理器的工厂
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");

        //4、从Factory中得到安全管理器
        SecurityManager securityManager = factory.getInstance();

        //5、把securityManager和Subject绑定到当前线程
        SecurityUtils.setSecurityManager(securityManager);

        //6、从SecurityUtils中得到subject
        Subject subject = SecurityUtils.getSubject();

        //7、去认证
        try {
            subject.login(token);
            System.out.println("认证通过");
        } catch (AuthenticationException e) {
            System.out.println("用户名或密码不正确");
        }
        /*
        catch (IncorrectCredentialsException e) {
            System.out.println("密码不正确");
        } catch (UnknownAccountException e) {
            System.out.println("用户名不存在");
        }
         */

        //8、查看认证状态
        System.out.println("认证状态:"+subject.isAuthenticated());

        //查看用户是否有role1的角色
        System.out.println("用户是否有role1的角色:"+subject.hasRole("role1"));
        //查看用户是否有role1、role2的角色
        List<String> list = new ArrayList<>();
        list.add("role1");
        list.add("role2");
        boolean[] isRoles = subject.hasRoles(list);
        for (boolean  isRole: isRoles) {
            System.out.println(isRole);
        }
        //查看用户是否有user:view的权限
        System.out.println(subject.isPermitted("user:view"));

        //9、退出
        subject.logout();
        System.out.println("认证状态:"+subject.isAuthenticated());
    }
}

注意,从以上的代码中可以看出我们的用户,密码,角色,权限都是在shrio.ini里面配置的,但是实际开发中我们的所有数据都是从数据库里面来的,如何实现呢,那就要使用数据和+自定义realm。

自定义Realm实现授权

//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    //创建授权对象
    SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
    //添加角色
    info.addRole("role1");
    info.addRole("role2");
    //添加权限
    info.addStringPermission("user:view");
    info.addStringPermission("user:create");
    info.addStringPermission("user:delete");
    info.addStringPermission("user:update");
    return info;
}

总结

Realm中有两个方法:doGetAuthenticationInfo()用作认证,doGetAuthorizationInfo()用作授权。当hasRoles()、hasRole()、isPermised()、isPermisedAll()方法被调用时,doGetAuthorizationInfo()方法就被执行一次。所以在开发中去查询用户权限的代码应该写在认证里面,因为认证只会执行一次。

在授权中可以用principals.getPrimaryPrincipal()方法获取认证中的SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password,this.getName());中的第一个参数。这个参数可以是任意类型。

所以一般在认证方法里面查询用户权限和角色之后使用一个ActiveUser类把用户、角色、权限封装传递给授权的方法。

posted @ 2020-10-08 00:18  coydone  阅读(197)  评论(0编辑  收藏  举报