精华内容
下载资源
问答
  • 权限校验
    千次阅读
    2022-03-29 10:15:29

    背景:在项目中,通常会给某些模块或者功能添加权限,只有有权限的人才能查看或者操作,本文记录下如何在项目中添加权限位的校验。
    实现
    1、在页面刷新的时候,通过接口获取当前用户所拥有的权限。
    在接口正常返回之后,将返回的权限存储到Vuex(也可以自行选择存储方式)中。
    代码如下:this.$store.commit('SET_AUTHS', "要存储的数据");
    2、在项目中封装权限校验的方法$auth(目录可在src下面的plugin中)

    import Vue from 'vue';
    Vue.use({
      install: function(Vue) {
        Vue.prototype.$auth = function(powers) {
            if (!powers) return true;
            if (typeof powers === 'string') {
              powers = [powers];
            }
    
            powers = powers || [];
    
            return !!powers.find(item => this.$store.state.session.auths.indexOf(item) > -1);
        };
        // 自定义账户校验方法(例如判断一个账户是不是低级)
        Vue.prototype.$isLowerAccount = function() {
          return this.$store.state.session.mem.accountLevel=== 1;
      };
        // 跳转到登录页面
        Vue.prototype.$gotologin = function(url) {
            url = url || '/#/login';
            const isProd = process.env.NODE_ENV === 'production';
            const loginURL = (isProd ? url : null) || '/#/login';
            window.location.href = loginURL;
        };
      }
    });
    

    :可以在其中自己添加需要使用的校验方法
    3、给模块或功能添加权限校验
    功能添加权限判断

    <v-list-item v-if="$auth('dept:update')" @click="showGroupEdit(checkedFirstGroup)">重命名</v-list-item>
    

    例如此按钮,直接在上面加上v-if对应的权限位,即可成功实现该功能的权限添加。
    模块添加权限判断
    如果是在菜单上,那么可如下定义菜单:

    menus: [
                    {
                        title: '首页',
                        isHome: true,
                        icon: 'ifHome',
                        iconColor: '#FFF',
                        link: '/',
                        path: '',
                        auth: 'homePage'
                    }
           ]
    

    在监听到权限存储的变化之后,给权限数组赋值:

     watch: {
            '$store.state.session.auths': {
                handler() {
                    this.myAuthMenus = JSON.parse(JSON.stringify(this.menus)).filter(item => {
                        if (!item.children) {
                            return this.$auth(item.auth) && (item.client ? this.$isClient(item.client) : true);
                        }
                        item.children = item.children.filter(child => {
                            if (!child.children) {
                                return this.$auth(child.auth) && (child.client ? this.$isClient(child.client) : true);
                            }
                            child.children = child.children.filter(sub => this.$auth(sub.auth) && (sub.client ? this.$isClient(sub.client) : true));
                            return child.children.length > 0;
                        });
                        return item.children.length > 0;
                    });
                },
                immediate: true
            }
        },
    

    :这里的**$isClient**是对环境的判断,如需要可在menus中菜单栏加。
    至此系统的权限校验生效。对于用户以及权限的获取更新操作,应在每次页面刷新时即去获取,因此应该将操作放在App.vue中进行。

    更多相关内容
  • 本篇文章主要介绍了Spring AOP实现功能权限校验功能的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 权限校验表设计

    2018-11-14 17:21:08
    基于Dubbo Filter,每次请求时通过【调用方(用户令牌)+服务标识+被调接口+调用参数】访问权限管理微服务获取具体权限
  • 深入浅出Git权限校验

    2021-02-01 11:30:12
    借助上次“掉坑”的经历,我对Git权限校验的两种方式重头进行了梳理,形成了这篇总结记录。 在本地计算机与GitHub(或GitLab)进行通信时,传输主要基于两种协议,HTTPS和SSH,对应的仓库地址就是HTTPS URLs和...
  • 本篇文章主要介绍了AngularJs HTTP响应拦截器实现登陆、权限校验,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
  • 自定义指令代码如下: import {CheckOperateEnum, checkPermissions, PermTypeEnum} from '@/utils/permissionUtils' /** * 权限校验命令,支持: * * 角色权限校验 * * 权限标识校验 * * 输入为字符串或者数组 * * ...

    使用场景:

    web后台项目都会有权限控制,可以分为两类,分别为页面权限操作权限

    • 页面权限:是指当前账号是否可以看到此页面;
    • 操作权限:是指当前账号在此页面可以做哪些操作

    很显然,账号必须先要能看到此页面,才能说在此页面能做的操作。如果连页面都看不到,具有的操作毫无意义,一般查看操作就是页面的权限,只能分配了查看操作的权限,才能在此页面进行其它操作。

    本文章只探讨操作权限的解决方案,页面权限后面再新建文章

    账号权限控制分类:

    账号权限控制主要分为账号具有的角色账号具有的权限标识

    • 角色 : 一个账号可以绑定多个角色,例如useradmintest等,不同的角色拥有不同的权限标识
    • 权限标识: 一个为有权限的操作,例如sys:user:selectsys:user:add分别表示可以对用户管理这个页面进行查看及新增操作。

    前端可以根据这两个权限信息来校验用户具有的页面权限操作权限

    例如(权限标识控制)

    一个用户管理页面,分别有查询、新增、修改、删除四个操作,且新增、修改、删除分别对应一个操作按钮,此4个操作分别对应的权限标识为sys:user:selectsys:user:createsys:user:updatesys:user:delete。当登录的账号具有sys:user:select权限标识时,才可以看到此页面,否则无法进入此页面。

    • 当用户具有sys:user:create权限标识时,才能看到(或者启用)新增按钮,实现新增操作。否则此按钮隐藏(或者禁用)

    • 当用户具有sys:user:update权限标识时,才能看到(或者启用)更新按钮,实现更新操作。否则此按钮隐藏(或者禁用)

    • 当用户具有sys:user:delete权限标识时,才能看到(或者启用)删除按钮,实现删除操作。否则此按钮隐藏(或者禁用)

    这样同一个管理后台,不同权限的账号登录进来看到的效果及其操作都是不一样的

    角色控制也是相同的原理。比如user角色具有查看更新的权限,admin具有全部的操作权限

    复杂场景

    一个操作,需要多个接口才能完成。还是以用户管理举例,例如搜索条件有部门的下拉框,而下拉框中的数据是通过调用接口来得到的。那么查询这个操作,除了sys:user:select权限标识外,还需要sys:org:list权限标识。新增操作也是如此,新增用户的时候也需要选择部门信息,那么除了sys:user:create权限标识外还需要其它权限标识才能完整的实现操作。

    总结:

    1. 权限标识一般和后台接口绑定,一个权限标识对应一个接口
    2. 一个操作可能需要多个接口才能完成功能

    前端操作权限的本质

    对于前端而言,操作权限的本质就是校验账号的具有的角色或者权限标识是否具有此按钮(或者dom)需要的角色或者权限标识,通过这个校验的结果来控制删除/禁用按钮(或者dom)或者显示/启用按钮(或者dom)

    例子

    例如有一个新增的按钮,需要有sys:user:create权限标识才能看到此按钮,伪代码如下

      if(isPerms('sys:user:create')){
         <!-- 有权限,显示按钮  -->
      	 <button>新增用户</button>
      }else{
           <!-- 没有权限不显示按钮  -->
      }
    

    从上面的结果来看,需要我们收到的操作dom元素,实现对dom的显示/隐藏或者启用/禁用。

    解决方案

    用vuex存储用户的所有角色及权限标识,并封装成判断的方法,VUE实例上挂载全局属性方法,方便所有组件调用,同时封装自定义指令,指令中的判断逻辑也是调用此判断方法。

    权限校验工具方法

    permissionUtils.js

    /**
     * 权限校验工具
     */
    import store from "@/store";
    
    /**
     * 权限校验的类型
     * @type {{ROLE: string, PERMS: string}}
     */
    export const PermTypeEnum = {
        PERMS: 'perms',
        ROLE: 'role'
    }
    
    /**
     * 权限校验的操作
     * @type {{OR: string, AND: string}}
     */
    export const CheckOperateEnum = {
        AND: 'and',
        OR: 'or'
    }
    
    /**
     *  检查是否具有全部资源权限
     * @param checkPerms {Array<String>}  检查的资源
     * @param allPerms {Array<String>}   具有的资源
     * @returns {Boolean}  true 具有权限  false 没有权限
     */
    export const checkPermsAll = (checkPerms, allPerms) => (checkPerms || []).every((perm) => allPerms.includes(perm))
    
    /**
     *  检查是否具有任意资源权限
     * @param checkPerms {Array<String>}  检查的资源
     * @param allPerms {Array<String>}   具有的资源
     * @returns {Boolean}  true 具有权限  false 没有权限
     */
    export const checkPermsAny = (checkPerms, allPerms) => (checkPerms || []).some((perm) => allPerms.includes(perm))
    
    /**
     * 权限校验
     * @param checkPerms {String|Array} 需要检查的权限
     * @param permType  权限的类型,角色或者权限标识
     * @param checkOperate  操作类型,且或者 是 或
     * @returns {Boolean}   是否具有权限, true 有权限, false 无权限
     */
    export const checkPermissions = (checkPerms,
                                     permType = PermTypeEnum.PERMS,
                                     checkOperate = CheckOperateEnum.AND) => {
        //得到用户具有的权限集合
        const perms = store.getters.perms
        // 得到用户具有的角色集合
        const roles = store.getters.roles.map(role => role.roleId)
        //权限判断结果
        const allPerms = []
        //开始判断是 角色权限校验 还是 权限校验 , 再判断是 或 操作 还是 与 操作
        if (permType === PermTypeEnum.ROLE) {
            allPerms.push(...roles)
        } else {
            allPerms.push(...perms)
        }
        //这里需要对校验的权限标记或者角色进行转换为数组
        const needCheckPerms = []
        if (checkPerms) {
            if ((checkPerms instanceof Array) && (checkPerms.length > 0)) {
                //如果输入数据为数组,则直接加入
                needCheckPerms.push(...checkPerms)
            } else if ((typeof checkPerms) === 'string') {
                needCheckPerms.push(checkPerms)
            }
        }
        let hasPerm = false;
        // 如果包含特殊标识,则视为管理员,全部放行
        if (allPerms.includes('*')) {
            hasPerm = true;
        } else {
            // 判断是 或 操作 还是 与 操作 , 如果给了or的修饰符,则表示为任意权限
            if (checkOperate === CheckOperateEnum.OR) {
                hasPerm = checkPermsAny(needCheckPerms, allPerms)
            } else {
                hasPerm = checkPermsAll(needCheckPerms, allPerms)
            }
        }
        return hasPerm;
    }
    
    export default {
        PermTypeEnum,
        CheckOperateEnum,
        checkPermissions
    }
    

    挂载到全局属性

    这里可以想到vue提供的v-if指令,再结合全局方法属性配合实现,在全局方法属性中提供权限校验,用v-if指令来实现操作dom。
    例子如下:

    import {checkPermissions} from "@/utils/permissionUtils";
    /**
     * 挂载全局 权限判断函数
     */
    Vue.prototype.isPerms = checkPermissions
    

    使用

     <button v-if="isPerms(['sys:user:create','sys:org:list'])">新增用户</button>
    

    此方案可以实现,但过于单一,不过灵活。如果需要扩展角色权限校验或者采用任意权限无法很好的扩展。

    自定义权限指令 (推荐

    注册vue的自定义指令,在自定义指令的钩子函数中提供绑定的参数及其dom,这样就可以进行dom操作。在自定义指令中dom元素挂载在父dom后,进行权限校验,如果权限不满足,则删除此dom
    自定义指令代码如下:

    import {CheckOperateEnum, checkPermissions, PermTypeEnum} from '@/utils/permissionUtils'
    
    /**
     * 权限校验命令,支持:
     * * 角色权限校验
     * * 权限标识校验
     * * 输入为字符串或者数组
     * * 任意权限或者全部权限校验
     * 使用例子 :
     *  权限标识校验:
     *    全部存在  v-permission="['sys:user:create','sys:user:list']" 或者 v-permission="'sys:user:create'"
     *    任意存在  v-permission.or="['sys:user:create','sys:user:list']"
     *
     *  角色权限校验:
     *    全部存在  v-permission:role="['user1','user2']" 或者 v-permission="'user'"
     *    任意任意  v-permission:role.or="['user1','user2']"
     *
     */
    export default {
    
        //被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
        /*
        el:指令所绑定的元素,可以用来直接操作 DOM。
        binding:一个对象,包含以下 property:
            name:指令名,不包括 v- 前缀。
            value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
            oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
            expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
            arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
            modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
        vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
        */
        inserted(el, binding, vnode) {
            // 得到指令的绑定值,此值为js计算完成后的值,当前为需要的权限
            const {value, arg, modifiers} = binding
            if (value) {
                //权限判断结果 , 这里会处理字符串及数组的情况
                const hasPermission = checkPermissions(value,
                    (arg === 'role') ? PermTypeEnum.ROLE : PermTypeEnum.PERMS,
                    modifiers.or ? CheckOperateEnum.OR : CheckOperateEnum.AND
                )
                if (!hasPermission) {
                    //如果没有权限则直接删除此节点
                    el.parentNode && el.parentNode.removeChild(el)
                }
            } else {
                throw new Error(`缺少权限标识 例如 v-permission="['sys:user:create','sys:user:list']" 或者 v-permission:role="['user']" `)
            }
        }
    }
    

    挂载指令

      Vue.directive('permission', permission)
    

    使用例子

      <div v-permission:role.or="['admin','role']">
          <span>admin和role角色都能看到我</span>
        </div>
    
        <div v-permission:role="['admin','user']">
          <span>必须同时有admin和user角色才能看到</span>
        </div>
    
        <div v-permission="['sys:user:select','sys:org:list']">
          <span>必须同时有sys:user:select和sys:org:list权限标识才能看到</span>
        </div>
    
        <div v-permission.or="['sys:user:select','sys:org:list']">
          <span>sys:user:select和sys:org:list权限标识都能看到我</span>
        </div>
    
    展开全文
  • 自定义注解实现RBAC权限校验,不再说你不会了

    千次阅读 多人点赞 2022-01-22 14:06:23
    拦截器+自定义注解实现RBAC权限校验,你绝对看得懂

    目录

    1、前言

    2、实现思路

    3、编码实战

    3.1、准备

    3.2、数据库表准备

    3.3、自定义注解

    3.4、拦截器

    3.5、接口使用

    3.6、测试

    3.7、结论

    4、结束语


    1、前言

    学过Spring Security的小伙伴都知道,SpringBoot项目可以集成Spring Security做权限校验框架,然后在Controller接口上直接使用@PreAuthorize注解来校验权限,但是如果我不想引入像Security、Shiro等第三方框架,也要实现权限校验的效果,该怎么做呢?

    接下来就给大家介绍一种方案:拦截器+自定义注解做基于RBAC模型的权限校验

    2、实现思路

    1. 首先数据库需要有基于RBAC模型的表,我们这里用最简单的5张表做示例:用户表、角色表、权限表、用户角色关联表、角色权限关联表

    2. 用户每次登录成功后,都需要联表查询该用户拥有的权限集合字符串,加密到token串中(此处可以使用JWT),返回给前端,前端存储到浏览器中,以后每次请求后台接口时,都将此token取出,放到请求头信息中,带到后台

    3. 然后新建自定义注解,该注解用于接口上面,表示该接口需要校验访问者的权限

    4. 新建拦截器,对所有请求方法的请求进行拦截,然后判断是否有自定义注解,如果有的话,取出权限字符串,和请求头中token的权限字符串集合进行比对,如果包含其中,则说明有权限访问该方法,如果不包含其中,就说明该用户没有权限访问该方法

    3、编码实战

    3.1、准备

    这里我准备了一个SpringBoot基础环境代码,我会在此基础上进行集成,代码我已上传,地址如下:

    SpringBootBase: SpringBoot基础项目框架

    基础薄弱的同学,可以下载下来,跟我下面的步骤一步一步走,就可以出来效果了,再集成到你自己的项目中

    3.2、数据库表准备

    5张表准备:

    用户表:

    CREATE TABLE `sys_user` (
      `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
      `dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
      `position_id` varchar(5) DEFAULT NULL COMMENT '职位ID',
      `class_id` bigint(20) DEFAULT NULL COMMENT '班级ID',
      `user_name` varchar(30) NOT NULL COMMENT '用户账号',
      `nick_name` varchar(30) NOT NULL COMMENT '用户昵称',
      `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)',
      `email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
      `phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码',
      `sex` char(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
      `avatar` varchar(300) DEFAULT '' COMMENT '头像地址',
      `password` varchar(100) DEFAULT '' COMMENT '密码',
      `status` char(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
      `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
      `login_ip` varchar(128) DEFAULT '' COMMENT '最后登录IP',
      `login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
      `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
      `create_time` datetime DEFAULT NULL COMMENT '创建时间',
      `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
      `update_time` datetime DEFAULT NULL COMMENT '更新时间',
      `remark` varchar(500) DEFAULT NULL COMMENT '备注',
      PRIMARY KEY (`user_id`),
      UNIQUE KEY `un_user_name` (`user_name`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息表';

    角色表:

    CREATE TABLE `sys_role` (
      `role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
      `role_name` varchar(30) NOT NULL COMMENT '角色名称',
      `role_key` varchar(100) DEFAULT NULL COMMENT '角色权限字符串',
      `role_sort` int(4) DEFAULT NULL COMMENT '显示顺序',
      `status` char(1) NOT NULL DEFAULT '0' COMMENT '角色状态(0正常 1停用)',
      `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
      `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
      `create_time` datetime DEFAULT NULL COMMENT '创建时间',
      `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
      `update_time` datetime DEFAULT NULL COMMENT '更新时间',
      `remark` varchar(500) DEFAULT NULL COMMENT '备注',
      PRIMARY KEY (`role_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色信息表';

    权限表:

    CREATE TABLE `sys_menu` (
      `menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
      `menu_name` varchar(50) NOT NULL COMMENT '菜单名称',
      `parent_id` bigint(20) DEFAULT '0' COMMENT '父菜单ID',
      `order_num` int(4) DEFAULT '0' COMMENT '显示顺序',
      `path` varchar(200) DEFAULT '' COMMENT 'menu_id全路径',
      `component` varchar(255) DEFAULT NULL COMMENT '组件路径',
      `query` varchar(255) DEFAULT NULL COMMENT '路由参数',
      `is_frame` int(1) DEFAULT '1' COMMENT '是否为外链(0是 1否)',
      `is_cache` int(1) DEFAULT '0' COMMENT '是否缓存(0缓存 1不缓存)',
      `menu_type` char(1) DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)',
      `visible` char(1) DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)',
      `status` char(1) DEFAULT '0' COMMENT '菜单状态(0正常 1停用)',
      `perms` varchar(100) DEFAULT NULL COMMENT '权限标识',
      `icon` varchar(100) DEFAULT '#' COMMENT '菜单图标',
      `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
      `create_time` datetime DEFAULT NULL COMMENT '创建时间',
      `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
      `update_time` datetime DEFAULT NULL COMMENT '更新时间',
      `remark` varchar(500) DEFAULT '' COMMENT '备注',
      PRIMARY KEY (`menu_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜单权限表';

    用户角色关联表:

    CREATE TABLE `sys_user_role` (
      `user_id` bigint(20) NOT NULL COMMENT '用户ID',
      `role_id` bigint(20) NOT NULL COMMENT '角色ID',
      PRIMARY KEY (`user_id`,`role_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户和角色关联表';

    角色权限关联表:

    CREATE TABLE `sys_role_menu` (
      `role_id` bigint(20) NOT NULL COMMENT '角色ID',
      `menu_id` bigint(20) NOT NULL COMMENT '菜单ID',
      PRIMARY KEY (`role_id`,`menu_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色和菜单关联表';

    3表联查,传入用户ID就可以查询出该用户拥有哪些权限字符串了,SQL如下:  

    select * from sys_menu t1
    left join sys_role_menu t2 on t1.menu_id = t2.menu_id
    left join sys_user_role t3 on t2.role_id = t3.role_id
    where t3.user_id = #{userId}

    3.3、自定义注解

    新建一个自定义注解:

    package org.wujiangbo.annotation;
    
    import java.lang.annotation.*;
    
    /**
     * 自定义注解校验权限
     */
    @Target({ ElementType.PARAMETER, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CheckPermission {
    
        /**
         * 权限字符串
         */
        String per() default "";
    }

    3.4、拦截器

    新建拦截器,代码如下:

    package org.wujiangbo.interceptor;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Component;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.wujiangbo.annotation.CheckPermission;
    import org.wujiangbo.exception.MyException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 权限校验拦截器
     */
    @Component
    public class CheckPermissionInterceptor implements HandlerInterceptor {
    
        /**
         * 前置处理
         * 该方法将在请求处理之前进行调用
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
            if (!(handler instanceof HandlerMethod)) {
                //说明拦截到的请求,不是请求方法的,那就直接放行
                return true;
            }
            //指定到这里,说明请求的是方法
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //获取方法对象
            Method method = handlerMethod.getMethod();
            //获取方法上面的 CheckPermission 注解对象
            CheckPermission methodAnnotation = method.getAnnotation(CheckPermission.class);
            if (methodAnnotation != null) {
                //获取权限字符串
                String per = methodAnnotation.per();
                if(StringUtils.isNotBlank(per)){
                    /**
                     * 说明需要校验权限,拥有该权限字符串,才能访问该方法
                     * 此时,需要从request头信息中拿到token,然后解密token,得到用户的权限集合,然后再做判断即可
                     */
                    //这里我们造点测试数据,假设从token中解析出当前登录用户的权限集合如下
                    List<String> userPermissionList = new ArrayList<>();
                    userPermissionList.add("user:addUser");
                    userPermissionList.add("user:deleteUser");
                    userPermissionList.add("user:updateUser");
                    userPermissionList.add("user:pageList");
    
                    //开始判断
                    if(!userPermissionList.contains(per)){
                        throw new MyException("您暂无权限进行此操作");
                    }
                }
            }
            //必须返回true,否则会拦截掉所有请求,不会执行controller方法中的内容了
            return true;
        }
    }

    需要将上面的拦截器类加入到web环境中,新建下面配置类:

    package org.wujiangbo.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
    import org.wujiangbo.interceptor.CheckPermissionInterceptor;
    
    /**
     * 统一拦截器配置类
     */
    @Configuration
    public class WebConfig extends WebMvcConfigurationSupport {
    
        @Autowired
        private CheckPermissionInterceptor checkPermissionInterceptor;
    
        //添加自定义拦截器
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(checkPermissionInterceptor).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
    }

    注意:

    我这里的拦截器中,没有对token进行解析,只是模拟了一下,实际项目中,token肯定是密文,无法直接使用的,需要先解析出用户拥有的权限集合字符串

    3.5、接口使用

    下面我们再controller接口中就可以直接使用了,如下:

    package org.wujiangbo.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.wujiangbo.annotation.CheckPermission;
    import org.wujiangbo.result.JSONResult;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * 测试接口类
     */
    @RestController
    @Slf4j
    public class TestController {
    
        //用户新增接口
        @GetMapping("/user/addUser")
        @CheckPermission(per = "user:addUser") //表示访问者需要具备 user:addUser 权限才能访问该接口
        public JSONResult addUser(){
            return JSONResult.success("addUser success");
        }
    
        //部门新增接口
        @GetMapping("/dept/addDept")
        @CheckPermission(per = "dept:addDept") //表示访问者需要具备 dept:addDept 权限才能访问该接口
        public JSONResult addDept(){
            return JSONResult.success("addDept success");
        }
    
    }

    3.6、测试

    用postman工具测试,先访问新增用户接口:http://localhost:8001/user/addUser

    再访问新增部门接口:http://localhost:8001/dept/addDept

    3.7、结论

    从测试结果可以看出,确实可以做到接口的权限校验,以后使用的话,可以直接在controller加个注解就可以了,非常的方便

    4、结束语

    • 这样的权限校验在实际工作中也有应用场景,希望大家都可以掌握哦

    • 大家如果还有任何疑问,可以留言,我会第一时间回复的

    • 最后别忘点赞哦,非常感谢大家的支持与厚爱,我会不断分享更多干货的哈

    展开全文
  • 微服务权限校验方案欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居...

    权限概述

    任何一个系统都绕不开权限这两个字,一个良好的权限设计对一个系统起到了非常重要的作用,其实权限设计是个范围很大的问题,包括从数据库的表设计,权限控制方案,前端权限可见控制等等,权限按控制类别区分又分菜单权限,功能权限和资源权限,前端后分离后又面临着接口权限等等控制(针对接口权限有一些常用的框架,如shiro,spring security等),权限又会出现功能上的叠加问题,比如写权限(新增)是否一定拥有读权限(查看);如果采用RBAC,多角色的权限叠加问题,如果允许用户直接赋权又会遇到用户权限与角色权限的叠加等等,特别实在微服务流行的当前,一个系统可能由几十个上百个服务组成,如果权限放到每个服务上去控制将会是一场噩梦,网上权限方案林林总总,可以说没有最好的权限方案,只有合适的权限。

    鉴权和权限控制

    相信有一些兄弟对鉴权和权限控制理不清概念,鉴权只是去判断用户是否能访问平台的一个控制,一般先通过校验用户名和密码后,通过session,token,OAuth等去判断用户是否处于登录状态,这里并没有针对功能权限或资源权限的控制,权限控制一般都是在鉴权的基础上去做,简而言之,鉴权是判断用户的登录状态,权限控制是针对用户功能权限,资源权限等的一个过滤和控制

    权限问题描述

    在这里插入图片描述
    目前我们系统的架构如上图所示,当前都是多节点,为了简化我只画了一个节点,我们权限系统包括要控制功能权限(菜单和按钮),资源权限,针对某类资源的一个权限控制,以及接口级别的权限控制。先说一下前提条件,我们是基于token的方式去做的鉴权,user-server提供用户的信息查询和权限查询功能,用户登录成功后,会将用户信息和权限信息(疑问一是否用户信息和权限信息要分开)缓存,然后gateway当请求过来是,判断请求head的token是否已经缓存,且能获取到用户信息,再往后释放请求。我这里数据库的数据采用RBAC,用户不直接配置权限。下面针对这个问题我列出我的疑问以及方法,希望能和大家一起讨论合适的方案

    • 权限功能叠加问题

    毫无疑问,写权限必定伴随着读权限,要不然我新增一条数据后无法看到这条数据,系统看上去问题就很大了,也就是说我们的写权限必须得继承我们的读权限,比如我们现在有个功能叫查看资源列表,另一个功能叫添加资源,如果我们添加资源,无法看到资源列表是不是功能上就有走不通了?
    但是我们在配置的时候我们勾选了添加功能未必一定会勾选查看列表的功能,那如何配置我们就可以新增资源拥有读的权限呢?
    在这里插入图片描述
    目前我想到两种方案:

    1. 将列表权限和菜单功能绑定,一旦拥有了资源管理这个菜单权限,则默认拥有了资源列表权限,这样将读权限上升一层,配置时无需考虑列表权限的问题
    2. 加权处理,上述功能虽然简单方便,但是将功能权限和菜单权限糅合在一起,对于没有列表功能或者后续需要删除列表功能,这样的需求扩展性就不高了,我们可以这么设计,假设资源列表权限的权限码是1,新增资源的权限码是2,我们存储用户新增权限时,存储的应该是1+2=3,这样我们就可以方便地处理权限的叠加功能(这里有个设计点,权限的码采用二进制1,2,4,8……,这样在做权限判断时可以使用未运行提升性能)
    • 统一功能(接口)权限问题
      在上述图中,我们可以清楚地知道,微服务模式下,如果每个服务自己去做权限校验,这会导致代码重复,扩展性低等等问题,那么,我们需要将权限统一处理(接口级别),这边想到的方式是将权限处理统一前置到网关层
      将权限控制到接口级别,则功能权限自然而然地就控制住了,那么怎么去控制接口级别地权限呢?
      在这里插入图片描述
      首先我们要讲功能与接口做一个绑定,我们可能在配置配置模块设计一个功能绑定接口的页面,这样可以动态去处理接口和功能间的映射,可能我们使用的是restful风格,所以如何去确定一个接口呢,我们需要这样几种属性
    1. 接口url,如:/api/res/1
    2. 接口请求方式,如:GET,POST,DELETE
    3. 如果服务比较多,为了避免重复也可以添加一个appcode去限定接口的范围

    如此我们可以在用户登录的时候读取用户的权限信息(有权限的接口信息),存放到redis缓存里面,然后用户再次请求时,gateway去缓存里面拿到接口信息和当前请求的接口信息做对比,继而判断当前用户是否有该接口的权限
    这里有个问题是如上图所示,当用户请求接口1时,他只有功能1的权限,功能2的权限是没有的,哪怕他第一个接口请求通过,后面的接口都会报403,前端就可以给出没有权限的判定

    • 数据权限问题
      数据权限我觉得应该是这个权限里面最难的,如果需要做数据权限必然是要满足以下几个场景

    1.该资源数据贯穿整个系统,整个系统是依附于该数据而创建的
    2.该数据挂载在某个组织树下,如部门组织结构

    如果不满足以上两点,资源权限的控制就非常复杂了,一是资源完全平铺,如数十万的数据在其中进行勾选配置功能毫无体验感,在做资源权限的校验sql中使用in大量数据效率也低下
    另外在微服务下,数据权限的校验则需要下放到各个微服务模块,因为数据权限的校验不具备全局通用性,我们在各个微服务模块可以使用aop的方式去判断当前用户当前接口是否拥有该资源的权限

    • 权限变更问题
      这个也是一个难点,比如用户的权限发生变更了,怎样让用户立马感知并更新权限呢?
      因为目前我们的权限信息是存放到缓存的,所以权限发生变更时需要更新缓存信息,目前有两种方式处理

    1.用户信息和权限信息缓存在同一个对象里面,此时如果权限发生变更,我们可以做用户的强制登出处理,这样用户再次登录就可以拿到新的权限信息(里面有些细节,比如角色的功能添加和删除,我们就需要找到该角色下绑定的在线用户,然后做统一登出处理,如此我们就需要维护在线用户的信息),此方式实现逻辑简单,唯一的麻烦是需要用户重新登录,体验较差
    2.用户信息和用户权限信息分开缓存,我们则会在权限信息发生变更时,删除用户的权限缓存,当用户再次请求时,发现没有权限信息,则重新去数据库获取,然后放到缓存,再做对比,此方式的好处是用户不用再次登录,我唯一担心的是用户信息和权限信息不一致的问题

    至此,权限方面的问题我都讲解了我的一些想法,当然也没法面面俱到,市面上的权限相关文章大多是理论层面的概述,于是记下此文,希望有相关需求的小伙伴能和我一起交流,共同成长

    展开全文
  • 主要介绍了vue路由权限校验功能的实现代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
  • SpringCloud微服务项目下的权限校验

    千次阅读 2021-12-15 15:40:05
    1.以前的单体架构权限验证 用户登录操作传入用户名和密码,传到后端,后端到DB里查询,如果查到就返回登录成功并把session信息存到内存中并把session的唯一标识(JessionId)返回给我们的浏览器,浏览器就会把我们...
  • springboot 权限校验

    千次阅读 2019-12-02 17:47:46
    用springboot做后台开发,难免会用到权限校验,比如查看当前用户是否合法,是否是管理员.而spring的面向切面的特性可以帮助我们很好的实现动态的权限校验.下面我们就用spring的aop和注解来快速的实现权限校验. 1....
  • INSERT INTO `tb_resource` VALUES (5, '登录权限', 'all:login'); INSERT INTO `tb_resource` VALUES (6, '登出权限', 'all:logout'); INSERT INTO `tb_resource` VALUES (7, '错误逻辑显示权限', 'all:error'); ...
  • ① 在权限表t_policy中新增两条数据: INSERT INTO `t_policy` VALUES ('fx-policy-fec8332fd0dc12f0000044', 'knowledgeEdit', '知识库编辑', 'knowledge', '知识库', '知识库编辑', 1, CURRENT_TIMESTAMP(), ...
  • spring cloud gateway 权限校验

    千次阅读 2020-10-03 18:01:35
    编写自定义的权限校验代码,并且使该过滤器在指定的路由上生效即可 如果权限校验需要使用到redis,则在gateway中需要引入redis的依赖 自定义token权限校验代码 /** * @calssName AppTokenFilter * @Description ...
  • Spring Security使用FilterSecurityInterceptor过滤器来进行URL权限校验,实际使用流程大致如下: 通过数据库动态配置url资源权限 系统启动时,通过FilterSecurityInterceptor滤器到数据库加载系统资源权限列表 ...
  • 业务多,逻辑复杂的情况下,可能不同的域名过来的请求、不同的路径就需要配置不同的权限校验方式,这种情况的话直接用全局过滤器似乎就不是很方便了。 用这种方式的话确实会比较灵活,但是……老实说业务太复杂了也...
  • springcloud+oAuth2网关如何做权限验证! 网关整合OAuth2.0有两种思路,一种是认证服务器生成jwt令牌,所有请求统一在网关层验证,判断权限等操作;另一种是由各资源服务处理,网关只做请求转发,这里为了做一个收口...
  • 登录及用户权限校验
  • // 如果没有添加权限注解则直接跳过允许访问 if (permission == null) { return true; } // 获取注解中的值 String resourceKey = permission.resourceKey(); // 校验逻辑 return "testKey".equals(resourceKey); }...
  • Nacos开启权限校验2. 服务注册3. 服务发现 1. Nacos开启权限校验        打开Nacos Server服务文件夹,进入到nacos\conf。打开application.properties文件,修改auth值,重启...
  • springboot拦截器主要目标: ...拦截请求,验证请求的用户对访问的资源是否有访问权限; 需要排除一些不在权限控制范围内的url,如swagger的接口文档列表; 需要排除的url,在配置文件中进行配置; 双拦截器
  • 何为AOP,AOP的注解详解,AOP的使用详例,以上内容尽在本文
  • 在编写接口api时,基于数据安全的考虑,我们通常会在接口进行权限校验,有权限的才可以查询数据,没有权限我们可以抛出异常“没有权限,禁止访问“。通常,我们实现是这样的: @ApiOperation("根据id查询用户信息...
  • spring cloud gateway权限校验

    千次阅读 2020-05-08 10:16:15
    spring cloud gateway权限校验可以整合security实现,我这里采用自定义filter简单实现,步骤如下: 1.首先配置RouteLocator,贴代码 @Configuration public class GatewayRoutes { @Autowired private ...
  • 1. 登陆权限,一般来说这个是独立出来,不用 spa 做,就一个表单的事情,后面也容易做扩展,包括单点登录什么的 2. 登陆集成到 spa 里面,这个一般在请求
  • 权限校验未通过 解决方式如下: 先排查了dcloud账号,云空间关联,如果均未发现问题,最后看下 uniCloud-aliyun/database配置下的 permission 权限配置问题,这里需要根据需要设置增删改查 create/delete/update/...
  • 微服务下的用户登录权限校验解决方案
  • MySQL 跳过权限校验

    千次阅读 2021-12-25 11:39:46
    如果忘记密码了,或者不小心修改了mysql.user表中中的记录,导致客户端连接不上MySQL了,可以在my.ini配置文件里增加下面一句话,保存,然后重启mysql服务,之后就可以连接上了。 skip-grant-tables ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 176,708
精华内容 70,683
关键字:

权限校验