shiro入门demo(二)授权

在前面认证的基础上,认证通过后进行授权操作。授权根据业务需求有两种维度,基于角色的授权和基于资源的授权。

一、授权-基于角色授权:

  shiro中授权实现方式:有三种

1、编程式
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
	//有权限
} else {
	//无权限
}

编程式又有两种方式:
 (1)hasRole、hasAllRoles 返回值true/false
 (2)checkRole、checkRoles 只要验证失败就报异常


2、注解式
@RequiresRoles("admin")
public void hello() {
	//有权限
}


3、标签式
JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成:

	

注意: Thymeleaf 中使用shiro需要额外集成!

 这里以第一种编程式为例

1、配置文件mock数据实现:

  新建shiro-user-role.ini配置文件

[users]
zs=123,role1
ls=123,role2
admin=123,role1,role2

 单元测试

  /**
     * 以admin/123用户为例
     */
    @Test
    public void testRole(){
        //1、创建SecurityManagerFactory 读取ini数据源文件
        IniSecurityManagerFactory factory=new IniSecurityManagerFactory("classpath:shiro-user-role.ini");
        //2、创建安全管理器SecurityManager
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        //3、通过SecurityUtil获取登入用户主体subject
        Subject subject = SecurityUtils.getSubject();
        //4、创建登入令牌token
        UsernamePasswordToken token=new UsernamePasswordToken(
                "admin", "123"
        );
        //用户认证(shiro的核心功能之一)
        try {
            //异常
            //1.org.apache.shiro.authc.UnknownAccountException:账号错误异常
            //2.org.apache.shiro.authc.IncorrectCredentialsException:密码错误异常
            //3.org.apache.shiro.authz.UnauthorizedException: 授权错误异常
            subject.login(token);
            System.out.println("认证成功");
        } catch (AuthenticationException e) {
            System.out.println("认证失败");
            e.printStackTrace();
        }
        //角色验证
        try {
            //方式一:hasRole 返回值true/false
            if (subject.hasRole("role1")) {
                System.out.println("角色验证成功");
            } else {
                System.out.println("角色验证失败");
            }
            //方式二:checkRole 只要验证失败就报异常
            //subject.checkRole("role1");
            //System.out.println("角色验证成功");

            //hasRoles: 参数List集合 返回boolean数组 返回顺序与传递顺序一一对应 传普通用户,高级用户,管理员 返回false,false,true
            //hasAllRoles: 参数Collection集合 返回true/false 如果有一个角色验证失败就返回false
        } catch (Exception e) {
            System.out.println("角色验证失败");
            e.printStackTrace();
        }

        //7、安全退出
        subject.logout();
    }

输出:认证成功 角色验证成功;

密码错误,角色正确,输出:

密码正确,改成错误的角色,输出:

2、Realm域实现:和下面资源授权合并,见下文。 

二、授权-基于资源授权 :

  资源权限编程式验证有两种方式:

(1)isPermitted、isPermittedAll方式,返回值true/false
(2)checkPermission、checkPermissions方式,只要验证失败就报异常

1、配置文件实现:

  新建shiro-user-role-permisson.ini配置文件:

[users]
zs=123,role1
ls=123,role2
admin=123,role1,role2,role4

[roles]
role1=system:user:add
role2=system:user:add,system:user:select
role3=system:user:add,system:user:select,system:user:update,system:user:delete
role4=system:*:*

  单元测试:在前面的基础上加上资源权限验证即可

 /**
     * 以admin/123用户为例
     */
    @Test
    public void testRole(){
        //1、创建SecurityManagerFactory 读取ini数据源文件
        IniSecurityManagerFactory factory=new IniSecurityManagerFactory("classpath:shiro-user-role-permisson.ini");
        //2、创建安全管理器SecurityManager
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        //3、通过SecurityUtil获取登入用户主体subject
        Subject subject = SecurityUtils.getSubject();
        //4、创建登入令牌token
        UsernamePasswordToken token=new UsernamePasswordToken(
                "admin", "123"
        );
        //用户认证(shiro的核心功能之一)
        try {
            //异常
            //1.org.apache.shiro.authc.UnknownAccountException:账号错误异常
            //2.org.apache.shiro.authc.IncorrectCredentialsException:密码错误异常
            //3.org.apache.shiro.authz.UnauthorizedException: 授权错误异常
            subject.login(token);
            System.out.println("认证成功");
        } catch (AuthenticationException e) {
            System.out.println("认证失败");
            e.printStackTrace();
        }
        //角色验证
        try {
            //方式一:hasRole 返回值true/false
            if (subject.hasRole("role3")) {
                System.out.println("角色验证成功");
            } else {
                System.out.println("角色验证失败");
            }
            //方式二:checkRole 只要验证失败就报异常
            //subject.checkRole("role1");
            //System.out.println("角色验证成功");

            //hasRoles: 参数List集合 返回boolean数组 返回顺序与传递顺序一一对应 传普通用户,高级用户,管理员 返回false,false,true
            //hasAllRoles: 参数Collection集合 返回true/false 如果有一个角色验证失败就返回false
        } catch (Exception e) {
            System.out.println("角色验证失败");
            e.printStackTrace();
        }
        try {
            //isPermitted方式
            if (subject.isPermitted("system:user:update")) {
                System.out.println("权限验证成功");
            } else {
                System.out.println("权限验证失败");
            }

            //checkPermission方式
            //subject.checkPermission("system:user:update");
            //System.out.println("权限验证成功");
        } catch (Exception e) {
            System.out.println("权限验证失败");
            e.printStackTrace();
        }
        //7、安全退出
        subject.logout();
    }

输出

输入错误的权限如system1:user:update,报错:

shiro入门demo(二)授权_第1张图片

Permission字符串通配符权限:

(1)规则:资源标志符:操作:对象实例id;

(2)*表示任意资源/操作/实例。

2、 Realm域实现:

(1)自定义域:

package com.demo.shiro.realm;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;

public class MyRolePermissionRealm1 extends AuthorizingRealm {

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        String primaryPrincipal = (String) principal.getPrimaryPrincipal();
        //用户名
        System.out.println("身份信息:"+primaryPrincipal);
         if(!"admin".equals(primaryPrincipal)){
            return null;
        }
        //根据用户查询角色、资源权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //1、角色
        simpleAuthorizationInfo.addRole("role1");
        simpleAuthorizationInfo.addRole("role2");
        //2、资源
        simpleAuthorizationInfo.addStringPermission("system:*:*");
        return simpleAuthorizationInfo;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        if(!"admin".equals(username)){
            throw new UnknownAccountException();
        }
        if(!"123".equals(password)){
            throw new IncorrectCredentialsException();
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,password,this.getName());
        return simpleAuthenticationInfo;
    }
}

以同样的方式实现zs、ls的授权Realm:

public class MyRolePermissionRealm2 extends AuthorizingRealm {

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        String primaryPrincipal = (String) principal.getPrimaryPrincipal();
        //用户名
        System.out.println("身份信息:"+primaryPrincipal);
        if(!"zs".equals(primaryPrincipal)){
            return null;
        }
        //根据用户查询角色、资源权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //1、角色
        simpleAuthorizationInfo.addRole("role1");
        //2、资源
        simpleAuthorizationInfo.addStringPermission("system:user:add");
        return simpleAuthorizationInfo;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        if(!"zs".equals(username)){
            throw new UnknownAccountException();
        }
        if(!"123".equals(password)){
            throw new IncorrectCredentialsException();
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,password,this.getName());
        return simpleAuthenticationInfo;
    }
}
public class MyRolePermissionRealm3 extends AuthorizingRealm {

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        String primaryPrincipal = (String) principal.getPrimaryPrincipal();
        //用户名
        System.out.println("身份信息:"+primaryPrincipal);
        if(!"ls".equals(primaryPrincipal)){
            return null;
        }
        //根据用户查询角色、资源权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //1、角色
        simpleAuthorizationInfo.addRole("role2");
        //2、资源
        simpleAuthorizationInfo.addStringPermission("system:user:add");
        simpleAuthorizationInfo.addStringPermission("system:user:select");
        return simpleAuthorizationInfo;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        if(!"ls".equals(username)){
            throw new UnknownAccountException();
        }
        if(!"123".equals(password)){
            throw new IncorrectCredentialsException();
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,password,this.getName());
        return simpleAuthenticationInfo;
    }
}

因为这里是多realm, doGetAuthorizationInfo中会传入多个doGetAuthenticationInfo传来的身份信息,所以加了判断只给指定用户设置权限。如果只有一个realm,则只会接收到一个身份,就不需要这个判断。

(2)单元测试:

 /**
     * 以admin/123用户为例
     */
    @Test
    public void testRole(){
       /* //1、创建SecurityManagerFactory 读取ini数据源文件
        IniSecurityManagerFactory factory=new IniSecurityManagerFactory("classpath:shiro-user-role-permisson.ini");
        //2、创建安全管理器SecurityManager
        SecurityManager securityManager = factory.getInstance();*/
        //编程设置realm
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        List realms = new ArrayList<>();
        realms.add(new MyRolePermissionRealm1());
        realms.add(new MyRolePermissionRealm2());
        realms.add(new MyRolePermissionRealm3());
        securityManager.setRealms(realms);
        SecurityUtils.setSecurityManager(securityManager);
        //3、通过SecurityUtil获取登入用户主体subject
        Subject subject = SecurityUtils.getSubject();
        //4、创建登入令牌token
        UsernamePasswordToken token=new UsernamePasswordToken(
                "admin", "123"
        );
        //用户认证(shiro的核心功能之一)
        try {
            //异常
            //1.org.apache.shiro.authc.UnknownAccountException:账号错误异常
            //2.org.apache.shiro.authc.IncorrectCredentialsException:密码错误异常
            //3.org.apache.shiro.authz.UnauthorizedException: 授权错误异常
            subject.login(token);
            System.out.println("认证成功");
        } catch (AuthenticationException e) {
            System.out.println("认证失败");
            e.printStackTrace();
        }
        //角色验证
        try {
            //方式一:hasRole 返回值true/false
            if (subject.hasRole("role1")) {
                System.out.println("角色验证成功");
            } else {
                System.out.println("角色验证失败");
            }
            //方式二:checkRole 只要验证失败就报异常
            //subject.checkRole("role1");
            //System.out.println("角色验证成功");

            //hasRoles: 参数List集合 返回boolean数组 返回顺序与传递顺序一一对应 传普通用户,高级用户,管理员 返回false,false,true
            //hasAllRoles: 参数Collection集合 返回true/false 如果有一个角色验证失败就返回false
        } catch (Exception e) {
            System.out.println("角色验证失败");
            e.printStackTrace();
        }
        try {
            //isPermitted方式
            if (subject.isPermitted("system:user:update")) {
                System.out.println("权限验证成功");
            } else {
                System.out.println("权限验证失败");
            }

            //checkPermission方式
            //subject.checkPermission("system:user:update");
            //System.out.println("权限验证成功");
        } catch (Exception e) {
            System.out.println("权限验证失败");
            e.printStackTrace();
        }
        //7、安全退出
        subject.logout();
    }

三、注解式授权:以上为编程式授权,shiro还提供了注解式授权:

1、@RequiresAuthentication:

要求当前Subject已经在session中验证通过(验证当前用户是否登录:subject.isAuthenticated() 结果为true)

2、@RequiresUser:

验证用户是否被记忆

3、@RequiresGuest:

用户没有登录认证或被记住过,验证是否是一个guest的请求,与@RequiresUser完全相反。换言之,RequiresUser == !RequiresGuest。此时subject.getPrincipal() 结果为null.

4、@RequiresRoles:

验证当前用户是否具有某角色,与验证权限类似

:5、@RequiresPermissions:

验证用户是否具有一个或多个权限,该注解将会经常在项目中使用,如果不满足条件则抛出AuthorizationException异常

你可能感兴趣的:(java)