shiro

在这里插入图片描述
在这里插入图片描述

shiro 权限管理

权限管理

权限管理分为认证和授权

认证

认证的基本概念

身份认证:校验用户是不是系统合法用户的过程(登录)

身份认证,就是判断一个用户是否为合法用户的处理过程

最常用的简单身份认证方式是系统通过核对用户输入的用户名和密码,看其是否与系统中存储的该用户的用户名和密码是否一致,来判断用户身份是否正确。

对于采用指纹等系统,则出示指纹;对于硬件Key等刷卡系统,则需要刷卡。通过二维码等等

在这里插入图片描述

认证基本的对象
Subject 主体

Without question, the most important concept in Apache Shiro is the Subject. ‘Subject’ is just a security term that means a security-specific ‘view’ of an application user. A Shiro Subject instance represents both security state and operations for a single application user.

毫无疑问,shiro中最重要的概念就是subject(主体)。subject是一个虚拟的用户对象(就是User Admin对象)。

在这里插入图片描述

使用Subject的之后的流程变化

在这里插入图片描述

Subject可以认为就是Admin User这些类

Credential 凭证信息 就是密码的意思

Principal 身份信息 就是账号的意思

扩展阅读:

We originally wanted to call it ‘User’ since that “just makes sense”, but we decided against it: too many applications have existing APIs that already have their own User classes/frameworks, and we didn’t want to conflict with those. Also, in the security world, the term ‘Subject’ is actually the recognized nomenclature.

我们最初是想把它叫做User的,这样很容易理解,但是大部分的应用程序都已经有了User类,为了不和这些原有的api发生冲突,我们最后决定不这么做。

认证的代码
导入依赖
<!--shiro相关依赖-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.3.2</version>
</dependency>
第一个demo

基本思路

用户输入的账号密码 和 数据库中存储的账号密码 比对

注意:shiro 默认不支持连接数据库 默认通过配置文件获取数据

  1. 接收用户输入的账号密码【模拟数据】
  2. 通过配置文件 模拟 用户在数据库中存储的账号密码
  3. 读取配置文件 将读取到数据( 用户在数据库中存储的账号密码) 将安全管理器 和Subject建立联系
  4. 将用户输入的账号密码给Subject
  5. 调用Subject的login方法完成登录

代码实现流程

  1. 定义ini配置文件

在这里插入图片描述

  1. 写测试类

    1. 接收用户输入的账号密码【模拟数据】
    2. 读取配置文件中的数据
    3. 将安全管理器 和Subject建立联系 通过工具类SecurityUtils、
    4. 通过工具类 获取Subject
    5. 调用登录方法 在调用登录方法的时候 通过令牌 把用户输入的账号密码给Subject
    6. 通过异常捕获 看看有没有登录成功
package com.baizhi;

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.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;

public class shiro {

    /**
     * 认证
     */
    @Test
    public void test1(){
        /**
         * 1.接收用户输入的账号密码【模拟数据】
         */
        String username = "zhangsan";
        String password = "123456";

        /**
         * 2.读取配置文件中的数据
         * IniSecurityManagerFactory ini安全管理器工厂  读取配置文件
         *
         * SecurityManager Shiro中的一个核心对象 认证实际上是需要通过安全管理器来完成的
         *
         * 获取安全管理器 相当于 把数据库中的账号密码 给了安全管理器
         */
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

        /**
         * 3.将安全管理器 和Subject建立联系
         *
         * 将安全管理器给工具类
         */
        SecurityUtils.setSecurityManager(securityManager);
        /**
         * 4.获取Subject
         *
         * 又通过工具类获取主体  单例
         */
        Subject subject = SecurityUtils.getSubject();

        /**
         * 5.调用登录方法 在调用登录方法的时候 通过令牌 把用户输入的账号密码给Subject
         *
         * 用户输入的账号密码 和 数据库中数据(模拟数据)  的比对是shiro框架自动完成  我们只负责给数据
         *
         * 参数 Token 令牌  封装账号密码
         *
         * 通过抛异常的方式 告诉程序员 有么有登录成功
         * 1.如果没有异常 登录成功
         * 2.UnknownAccountException 账号不存在
         * 3.IncorrectCredentialsException 密码不正确
         *
         */
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try{
            subject.login(token);
            System.out.println("登录成功");
        }catch (UnknownAccountException e){
            System.out.println("账号不存在");
        }catch (IncorrectCredentialsException e){
            System.out.println("密码不正确");
        }
//        Authenticate 认证  isAuthenticated();检验当前的主体有么有认证成功
        boolean authenticated = subject.isAuthenticated();
        System.out.println(authenticated);
    }
}
修改认证的数据源(认证源码)
为什么要修改数据源

因为默认的认证:从配置文件中获取数据 需要修改为从数据库中获取

默认的认证:从配置文件中获取数据

通过阅读源码 分析 默认是如何获取数据的

跟着一个具体方法走 login方法

在这里插入图片描述

debug模式使用

  1. 打断点

在这里插入图片描述

  1. 运行debug模式

    1. 一般运行

    在这里插入图片描述

    1. 插件运行

在这里插入图片描述

  1. IDEA debug模式控制面板

在这里插入图片描述

源码过程【参考了解即可】

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

解决方案!

根据源码 默认SimpleAccountRealm类中的doGetAuthenticationInfo方法的实现 是查询配置文件中的数据

可以继承AuthenticatingRealm类(父类) 重写 doGetAuthenticationInfo方法(抽象方法)

重写Realm的代码!
package com.baizhi.realm;

import com.baizhi.dao.CmfzAdminDao;
import com.baizhi.entity.CmfzAdmin;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.springframework.beans.factory.annotation.Autowired;

import java.security.Principal;

public class MyRealm extends AuthenticatingRealm {
    @Autowired
    private CmfzAdminDao cmfzAdminDao;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//        1.获取令牌中的数据 账号
        UsernamePasswordToken passwordToken = (UsernamePasswordToken) token;
        String username = passwordToken.getUsername();
//        2.通过账号获取数据库对应的账户信息
        CmfzAdmin admin = cmfzAdminDao.selectOne(new QueryWrapper<CmfzAdmin>().eq("username", username));
//        3.如果有数据 对象非null  封装account返回
        if (admin != null) {
//            Principal 身份信息 账号
            return new SimpleAccount(admin.getUsername(),admin.getPassword(),this.getName());
        }
//        4.如果对象为null 直接return null  就会抛账户不存在异常
        return null;
    }
}

作业:

  1. 回顾所有的概念
  2. 练习MyRealm Demo
SpringBoot集成shiro认证
在SpringBoot中配置shiro
package com.baizhi.config;

import com.baizhi.realm.MyRealm;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.config.WebIniSecurityManagerFactory;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;


/**
 * @Configuration 标记当前类为配置类  相当于spring.xml
 */
@Configuration
public class ShiroConfig {

    /**
     * @Bean 声明创建对象  并把对象放在工厂中  相当于bean标签
     * 如果形参类型对应的对象在工厂中有  会自动装配上
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultSecurityManager defaultSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        /**
         * 过滤器链 过滤拦截规则 哪些页面拦截  哪些页面不拦截
         */
        HashMap map = new HashMap();
        /**
         * anon 代表匿名可访问 就是不用登录就可以访问  登录页面  登录的url
         *
         * authc 认证可访问 代表登录后才能访问
         *
         * 支持通配符*
         *
         * 注意拦截规则 一个一个配置
         */
        map.put("/login.jsp","anon");
        map.put("/login/*","anon");

        map.put("/main/*", "authc");
        map.put("/guru/*", "authc");
        map.put("/menu/*", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        /**
         * 设置安全管理器
         */
        shiroFilterFactoryBean.setSecurityManager(defaultSecurityManager);


        return shiroFilterFactoryBean;
    }

    /**
     * 创建安全管理器
     * @return
     */
    @Bean
    public DefaultSecurityManager getDefaultSecurityManager(MyRealm myRealm){
        DefaultSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
//        需要赋值一个Realm
        defaultSecurityManager.setRealm(myRealm);
        return defaultSecurityManager;
    }

    /**
     * 创建自定义的Realm
     */
    @Bean
    public MyRealm getMyRealm(){
        return new MyRealm();
    }
}

注意:需要修改的是 拦截规则 和 自定义的Realm

修改原来的登录方法
    /**
     * 使用shiro登录
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("adminLogin")
    public String adminLogin(String username,String password){
//        1.将用户输入的账号密码 封装在token中
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

//        2.获取Subject
        Subject subject = SecurityUtils.getSubject();

//        3.通过Subject 的login方法 完成登录
        try {
            subject.login(token);
            return "redirect:/main/main.jsp";

        }catch (Exception e){
            
            return "redirect:/login.jsp";
        }
    }
Session的使用

方案1:HttpSession

方案2:shiro中的session

Session session1 = SecurityUtils.getSubject().getSession();

注意:方案1 和 方案2 都可以 使用 但是只能使用一种方案 不要混合使用

认证总结

认证:登录,身份认证,校验用户是不是系统合法用户的过程

主体Subject:就是Admin,User这些类,但是和之前自己定义的User Admin稍以后区别,Subject不仅封装用户和认证相关的数据(账号密码),还封装了和认证相关的方法(login方法)

Credential 凭证信息 就是密码的意思

Principal 身份信息 就是账号的意思

重写Realm中的方法

  1. 为什么要重写Realm中的方法

    默认不支持连接数据库 默认的实现是查询配置文件

  2. 解决方案

    shiro默认的doGetAuthenticationInfo方法是查询配置文件,由于这个方法是父类的一个抽象方法,通过继承和多态,可以继承父类,覆盖这个方法(在方法中写入我们新的方法实现 连接数据库 查询数据库中的账号信息)

集成项目的基本流程

  1. 写shiro的配置类(创建对象)

    注意:拦截规则 和 自定义的Realm 需要根据自己项目的情况调整

  2. 修改原来的登录方法

作业:

修改登录方法为shiro登录

授权Authorization

授权的基本概念

在这里插入图片描述

Authorization, also known as access control, is the process of managing access to resources. In other words, controlling who has access to what in an application.

Examples of authorization checks are: Is the user allowed to look at this webpage, edit this data, view this button, or print to this printer? Those are all decisions determining what a user has access to.

授权,也称为访问控制,是管理对资源的访问的过程。换句话说,控制谁有权利访问应用程序中的哪些内容。控制不同等级的人能够看到不同的东西,做不同的事儿

授权相关的概念
资源

资源 一切都是资源 对于持明法洲项目 资源指的是数据 【库表】 例如:上师表

**资源类型:**上师 轮播图 等 资源的分类的类名

**资源实例:**具体类型中的某一个 库表中的一条数据 例如:id为1 的上师数据 是资源实例

权限 permission

权限(权利):可以对资源做什么事儿 对资源的具体操作 这种行为的描述

上师表 — 资源

查询上师数据

添加上师数据

修改上师数据

删除上师数据

角色 role

在这里插入图片描述

作业:

设计2班的资源 权限 角色的模型

授权的代码
授权的基本流程

先认证后授权

在这里插入图片描述

权限如何保存在shiro中 【权限字符串】

查询上师数据 guru:select

添加上师数据 guru:insert

修改上师数据 guru:update

删除上师数据 guru:delete

操作描述 在shiro框架中怎么写?

权限字符串的语法

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

权限的汉语描述权限字符串 资源类型:操作:实例
展示轮播图banner:show
展示id为10的轮播图banner:show:10
删除轮播图banner:delete
具有轮播图相关的所有权限banner:*
删除上师guru:delete
授权的第一个demo

写在测试类中 授权默认也不支持连接数据库

  1. 在配置文件中写入假数据

    认证的数据

    授权的数据

在这里插入图片描述

  1. 写测试代码 【先认证后授权】

        /**
         * 先认证后授权
         */
        @Test
        public void test2(){
    //        1.用户输入的账号密码
            String username = "lilei";
            String password = "123456";
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    //        2.读取配置文件 创建安全管理器
            IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = factory.getInstance();
    
    //        3.将安全管理器给工具类
            SecurityUtils.setSecurityManager(securityManager);
    
    //        4.通过工具类获取主体
            Subject subject = SecurityUtils.getSubject();
    
    //        5.认证
            try {
                subject.login(token);
                System.out.println("登录成功");
            }catch (Exception e){
                System.out.println("登录失败");
            }
    
    //        6.通过方法校验是否登录成功
            boolean authenticated = subject.isAuthenticated();
            if (authenticated){
    //            代表登录成功
    
                /**
                 * 进行授权操作 代码式授权
                 * hasRole("vip1") 返回值为true 代表当前用户拥有 vip1的角色
                 */
                boolean vip1 = subject.hasRole("vip1");
                if (vip1){
                    System.out.println("调用查询上师的方法");
                }
                
                /**
                 * subject.isPermitted("guru:select") 返回值为true 代表当前用户拥有 查询上师的权限
                 */
                boolean permitted = subject.isPermitted("guru:select");
                if (permitted){
                    System.out.println("调用查询上师的方法");
                }else {
                    System.out.println("当前用户没有权限 不能操作");
                }
            }
        }
    
授权的通用数据模型

用户 角色 权限 的关系 怎么通过库表来保存?

在这里插入图片描述

用户表

用户 和 角色 多对多 一个用户可以有多个角色 一个角色可以分配给多个用户

角色表

角色 和 权限 多对多 一个角色可以有多个权限 一个权限可以分配给多个角色

权限表

多对多关系通过添加中间表处理

在这里插入图片描述

作业:

  1. 练习授权的demo
  2. 在数据库中导入库表 看一看
  3. 写两个业务层方法
    1. 根据用户名查询用户拥有的所有权限 返回值类型为 Set<String>
    2. 根据用户名查询用户拥有的所有角色 返回值类型为Set<String>
修改授权数据源

默认获取配置文件中的数据 授权数据的获取

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

解决方案

  1. 继承 AuthorizingRealm 类(授权的父类 抽象) 覆盖类中的方法
集成SpringBoot
  1. 创建一个自定义授权的Realm (授权的Realm中有两个方法 获取认证信息和授权信息 所以之前的MyRealm类就不需要了)

    package com.baizhi.realm;
    
    import com.baizhi.dao.CmfzAdminDao;
    import com.baizhi.entity.CmfzAdmin;
    import com.baizhi.service.CmfzRoleService;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    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.subject.PrincipalCollection;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.Set;
    
    public class AuthorRealm extends AuthorizingRealm {
        @Autowired
        private CmfzAdminDao cmfzAdminDao;
        @Autowired
        private CmfzRoleService cmfzRoleService;
    
        /**
         * 获取授权信息
         * @param principals
         * @return
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    //        1.获取用户名  getPrimaryPrincipal() 获取主身份  就是用户名
            String username = principals.getPrimaryPrincipal().toString();
    
    //        2.查询数据库 获取用户对应的角色信息和权限信息
            Set<String> roles = cmfzRoleService.getAllRolesByUsername(username);
            Set<String> permissions = cmfzRoleService.getAllPermissionsByUsername(username);
    
    //        3.封装info
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.setStringPermissions(permissions);
            info.setRoles(roles);
    
            return info;
        }
    
        /**
         * 获取认证信息
         * @param token
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    //        1.获取用户名
            UsernamePasswordToken passwordToken = (UsernamePasswordToken) token;
            String username = passwordToken.getUsername();
    
    //        2.查询数据库
            CmfzAdmin cmfzAdmin = cmfzAdminDao.selectOne(new QueryWrapper<CmfzAdmin>().eq("username", username));
            if (cmfzAdmin != null) {
                //        3.封装info
                return new SimpleAuthenticationInfo(cmfzAdmin.getUsername(), cmfzAdmin.getPassword(), this.getName());
            }
            return null;
        }
    }
    
  2. 修改shiro配置 修改MyRealm 为新的授权的Realm

在这里插入图片描述

多种授权方式
  1. 代码式授权

    //            代码式授权
                if (subject.hasRole("admin")) {
                    System.out.println("具有admin的角色");
                    System.out.println("调用了支付宝给自己转钱的方法");
                }
    
                if (subject.isPermitted("banner:create")) {
                    System.out.println("可以添加轮播图");
                }
    
  2. 注解式授权 如果没有权限 访问不了对应的方法

    1. 配置在shiro配置类

      /**
       *  开启shiro aop注解支持
       *  使用代理方式;所以需要开启代码支持;否则@RequiresRoles等注解无法生效
       * @param securityManager
       * @return
       */
      @Bean
      public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultSecurityManager securityManager){
          AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
          authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
          return authorizationAttributeSourceAdvisor;
      }
      

    在这里插入图片描述

    1. 在方法上直接使用注解 没有权限就报错

      /**
       * @RequiresPermissions(value = "guru:download") 当用户拥有 下载上师 的权限才能访问该方法
       * @throws IOException
       */
      @RequiresPermissions(value = "guru:download")
      
      
      /**
           *  @RequiresRoles(value = "admin") 用户具有了admin的角色才能访问当前方法
           * @return
           */
      @RequiresRoles(value = "admin")
      

      在这里插入图片描述

      在这里插入图片描述

  3. 标签式授权(Jsp页面中) 根据用户的权限不同 显示不一样的页面效果

    1. 引入标签库

      <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
      
    2. 使用

    <%@page isELIgnored="false" pageEncoding="UTF-8" contentType="text/html; UTF-8" %>
    <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
    
    <%--如果有guru:add权限 按钮才会显示--%>
    <shiro:hasPermission name="guru:add">
        <button>添加上师</button>
    </shiro:hasPermission>
    <%--如果有banner:create权限 按钮才会显示--%>
    <shiro:hasPermission name="banner:create">
        <button>添加轮播图</button>
    </shiro:hasPermission>
    
    <shiro:hasRole name="admin">
        <h3>有admin的角色可以显示</h3>
    </shiro:hasRole>
    <shiro:hasRole name="superadmin">
        <h3>有superadmin的角色可以显示</h3>
    </shiro:hasRole>
    
    获取用户名:<shiro:principal/>
    
相关知识
架构图

在这里插入图片描述

有哪些常用的API?讲代码中的

RBAC 权限模型

角色 权限 用户 之间的关系 【表关系】

  1. 基于角色
  2. 基于权限

基于角色的访问控制

RBAC基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制,比如:主体的角色为总经理可以查询企业运营报表,查询员工工资信息等,访问控制流程如下:

在这里插入图片描述
上图中的判断逻辑代码可以理解为:

if(主体.hasRole("总经理角色id")){
	查询工资
}

缺点:以角色进行访问控制粒度较粗,如果上图中查询工资所需要的角色变化为总经理和部门经理,此时就需要修改判断逻辑为“判断主体的角色是否是总经理或部门经理”,系统可扩展性差。

修改代码如下:

if(主体.hasRole("总经理角色id") ||  主体.hasRole("部门经理角色id")){
	查询工资
}

基于资源的访问控制

RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制,比如:主体必须具有查询工资权限才可以查询员工工资信息等,访问控制流程如下:

在这里插入图片描述

上图中的判断逻辑代码可以理解为

if(主体.hasPermission("查询工资权限标识")){
	查询工资

}	

总经理 工资权限标识
部门经理 工资权限标识

优点:系统设计时定义好查询工资的权限标识,即使查询工资所需要的角色变化为总经理和部门经理也只需要将“查询工资信息权限”添加到“部门经理角色”的权限列表中,判断逻辑不用修改,系统可扩展性强。

作业:

  1. 练习demo
  2. 写两个业务层方法
    1. 根据用户名查询用户拥有的所有权限 返回值类型为 Set<String>
    2. 根据用户名查询用户拥有的所有角色 返回值类型为Set<String>
  3. 授权集成SpringBoot
  4. 找一个页面 练习标签式授权
  5. 找个业务层类 练习注解式授权

ess Control)是以角色为中心进行访问控制,比如:主体的角色为总经理可以查询企业运营报表,查询员工工资信息等,访问控制流程如下:

[外链图片转存中…(img-3KsoaR3T-1577550762884)]

上图中的判断逻辑代码可以理解为:

if(主体.hasRole("总经理角色id")){
	查询工资
}

缺点:以角色进行访问控制粒度较粗,如果上图中查询工资所需要的角色变化为总经理和部门经理,此时就需要修改判断逻辑为“判断主体的角色是否是总经理或部门经理”,系统可扩展性差。

修改代码如下:

if(主体.hasRole("总经理角色id") ||  主体.hasRole("部门经理角色id")){
	查询工资
}

基于资源的访问控制

RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制,比如:主体必须具有查询工资权限才可以查询员工工资信息等,访问控制流程如下:

[外链图片转存中…(img-bc55wZ9e-1577550762885)]

上图中的判断逻辑代码可以理解为

if(主体.hasPermission("查询工资权限标识")){
	查询工资

}	

总经理 工资权限标识
部门经理 工资权限标识

优点:系统设计时定义好查询工资的权限标识,即使查询工资所需要的角色变化为总经理和部门经理也只需要将“查询工资信息权限”添加到“部门经理角色”的权限列表中,判断逻辑不用修改,系统可扩展性强。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

明月清风,良宵美酒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值