3、Shiro的授权

1、 授权方式

基于角色的访问控制

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:*")){  //资源类型
  //对 所有的资源 用户具有更新的权限
}

2、权限字符串

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

例子:

  • 用户创建权限:user:create,或user:create:*
  • 用户修改实例001的权限:user:update:001
  • 用户实例001的所有权限:user:*:001

3、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需要额外集成!

授权代码编写:

1.realm的实现
package com.laity.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * @author: laity
 * @date: 2022/5/9 9:29 下午
 * @description: 使用自定义real加入md5+salt+hash
 */
public class CustomerRealmMD5 extends AuthorizingRealm {

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
         String principal = (String) principalCollection.getPrimaryPrincipal();
         System.out.println("身份信息" + principal);

         //根据用户名获取当前的用户角色信息,以及权限信息
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //将数据库查询的数据赋值给SimpleAuthorizationInfo
        simpleAuthorizationInfo.addRole("admin");
        simpleAuthorizationInfo.addRole("user");


        ////假设 ... 是从数据库查到的 权限信息赋值给权限对象
        simpleAuthorizationInfo.addStringPermission("user:*:01");
        simpleAuthorizationInfo.addStringPermission("product:create");
        return simpleAuthorizationInfo;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取身份信息
        String principal = (String) authenticationToken.getPrincipal();

        if("xiaowang".equals(principal)){
            return new SimpleAuthenticationInfo(principal,
                    "81c97817c4e4db0baa3ebd97ad2afebb",
                    ByteSource.Util.bytes("XO*7ps"),
                    this.getName());
        }
        return null;
    }
}

2.授权
package com.laity.test;

import com.laity.realm.CustomerRealmMD5;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

import java.util.Arrays;

/**
 * @author: laity
 * @date: 2022/5/9 9:31 下午
 * @description: 测试加入MD5的Realm
 */
public class TestCustomerAuthenticatorMD5 {

    public static void main(String[] args) {

        //创建安全管理器
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();

        //注入realm
        CustomerRealmMD5 realm =new CustomerRealmMD5();

        //设置realm使用hash凭证匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //使用算法
        credentialsMatcher.setHashAlgorithmName("md5");
        //散列次数
        credentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(credentialsMatcher);

        defaultSecurityManager.setRealm(realm);
        //将安全管理器注入安全工具
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //通过安全类获取subject
        Subject subject = SecurityUtils.getSubject();

        //获取token
        UsernamePasswordToken token = new UsernamePasswordToken("xiaowang", "123456");

        //进行认证
        try{
            subject.login(token); //用户认证
            System.out.println(subject.isAuthenticated());
            System.out.println("登录成功");
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("认证失败:用户名不存在");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("认证失败:密码错误");
        }

        //授权

        if (subject.isAuthenticated()){
            //基于角色权限控制
            System.out.println(subject.hasRole("user"));
            //基于多角色的权限控制
            System.out.println(subject.hasAllRoles(Arrays.asList("user", "super")));

            //多角色是否具有其中的一个角色
            boolean[] booleans = subject.hasRoles(Arrays.asList("user", "super"));
            for (boolean aBoolean : booleans) {
                System.out.println(aBoolean);
            }
        }
        System.out.println("---------------------------------------------------");
        //基于权限字符串的认证  资源标识符:操作:资源类型
        if (subject.isAuthenticated()){
            System.out.println("字符串权限认证"+subject.isPermitted("user:*:01"));
            System.out.println("字符串权限认证"+subject.isPermitted("product:create:02"));

            //分别具有哪些权限
            boolean[] permitted = subject.isPermitted("user:*:01", "order:*:10");

            for (boolean b : permitted) {
                System.out.println(b);
            }

            //同时具有哪些权限认证
            System.out.println(subject.isPermittedAll("user:*:01", "product:create:01"));

        }
    }

}

posted @ 2022-05-10 20:21  不起眼的程序员  阅读(74)  评论(0编辑  收藏  举报