改造开源框架guns增加对数据内容访问权限的相关实现

这篇博客记录了在guns 7.1.2版本中增加数据内容访问权限的实现过程。通过创建DataScopePropertyUtil类,设置数据权限属性,并在控制器和服务层中进行赋值和查询语句的修改,确保了用户数据范围的过滤。同时,文章提到了在SysUserMapper.xml中针对不同数据库的SQL拼接,以适应数据权限的查询需求。
摘要由CSDN通过智能技术生成

改造开源框架guns增加对数据内容访问权限的相关实现


使用guns框架已经有一段时间了,前端时间发现stylefeng发布了7.1.2的版本,对比之前的版本做了重大的改变,新架构的思想看起来很先进,刚好有新项目要做,所以决定用这个新版本来进行。
做了一部分之后发现,新版本的guns中好像未对数据内容的访问权限进行实现,只能自己研究实现了。
以下是实现步骤,在此做记录。

  1. 在kernel-d-auth中增加类,cn.stylefeng.roses.kernel.auth.api.util.DataScopePropertyUtil
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.enums.DataScopeTypeEnum;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.Set;

@Slf4j
public class DataScopePropertyUtil {
    /**
     * 设置查看权限属性
     * @param object
     */
    public static void setDataScopParam(Object object,SessionManagerApi sessionManagerApi){
        String token = null;
        try {
            token = LoginContext.me().getToken();
        } catch (Exception e) {
            // 不做处理,因为本接口可能是不需要鉴权
        }
        LoginUser user = sessionManagerApi.getSession(token);
        boolean isManage =  user.getSuperAdmin();
        if(!isManage){
            try{
                if(user.getDataScopeTypeEnums().contains(DataScopeTypeEnum.SELF)) {
                    Method method = object.getClass().getMethod("setDataScopeUserIds", Set.class);
                    if (method != null) {
                        method.invoke(object, new Object[]{user.getDataScopeUserIds()});
                    }
                }
                if(user.getDataScopeTypeEnums().contains(DataScopeTypeEnum.DEPT) || user.getDataScopeTypeEnums().contains(DataScopeTypeEnum.DEPT_WITH_CHILD)
            || user.getDataScopeTypeEnums().contains(DataScopeTypeEnum.DEFINE)) {
                    Method method = object.getClass().getMethod("setDataScopeOrganizationIds", Set.class);
                    if (method != null) {
                        if(user.getDataScopeOrganizationIds() != null)
                            method.invoke(object, new Object[]{user.getDataScopeOrganizationIds()});
                    }
                }
            }catch (Exception e){
                log.error("setDataScopParam error. ",e);
            }
        }
    }
}
  1. 增加属性,SysUserRequest HrOrganizationRequest
    /**
     * 用户数据范围用户信息
     */
    @ChineseDescription("用户数据范围用户信息")
    private Set<Long> dataScopeUserIds;

    /**
     * 用户数据范围组织信息
     */
    @ChineseDescription("用户数据范围组织信息")
    private Set<Long> dataScopeOrganizationIds;
  1. 修改HrOrganizationController

1). 增加成员变量

    @Resource
    private SessionManagerApi sessionManagerApi;

2). 增加访问权限赋值 DataScopePropertyUtil.setDataScopParam(hrOrganizationRequest,sessionManagerApi);

    /**
     * 获取全部系统组织机构树(用于新增,编辑组织机构时选择上级节点,用于获取用户管理界面左侧组织机构树)
     *
     * @author chenjinlong
     * @date 2021/01/05 15:55
     */
    @GetResource(name = "获取全部系统组织机构树", path = "/hrOrganization/tree", responseClass = OrganizationTreeNode.class)
    public ResponseData organizationTree(HrOrganizationRequest hrOrganizationRequest) {
        DataScopePropertyUtil.setDataScopParam(hrOrganizationRequest,sessionManagerApi);
        return new SuccessResponseData(hrOrganizationService.organizationTree(hrOrganizationRequest));
    }
    /**
     * 分页查询系统组织机构
     *
     * @author fengshuonan
     * @date 2020/11/04 11:05
     */
    @GetResource(name = "分页查询系统组织机构", path = "/hrOrganization/page", responseClass = HrOrganization.class)
    public ResponseData page(HrOrganizationRequest hrOrganizationRequest) {
        DataScopePropertyUtil.setDataScopParam(hrOrganizationRequest,sessionManagerApi);
        return new SuccessResponseData(hrOrganizationService.findPage(hrOrganizationRequest));
    }
  1. 修改HrOrganizationServiceImpl.java
       /**
        * 根据数据范围获取组织机构列表
        *
        * @author fengshuonan
        * @date 2021/2/8 20:22
        */
       private List<HrOrganization> findListByDataScope(HrOrganizationRequest hrOrganizationRequest) {
   
           LambdaQueryWrapper<HrOrganization> queryWrapper = this.createWrapper(hrOrganizationRequest);
   
           // 数据范围过滤
           // 如果是超级管理员,或者数据范围权限是所有,则不过滤数据范围
           boolean needToDataScope = true;
           Set<DataScopeTypeEnum> dataScopeTypes = LoginContext.me().getLoginUser().getDataScopeTypeEnums();
           if (LoginContext.me().getSuperAdminFlag() || (dataScopeTypes != null && dataScopeTypes.contains(DataScopeTypeEnum.ALL))) {
               needToDataScope = false;
           }
   
           // 过滤数据范围的SQL拼接
           if (needToDataScope) {
               // 获取用户数据范围信息
               Set<Long> dataScope = LoginContext.me().getLoginUser().getDataScopeOrganizationIds();
               log.warn("#####   "+Arrays.toString(dataScope.toArray()));
               // 如果数据范围为空,则返回空数组
               if (ObjectUtil.isEmpty(dataScope)) {
                   return new ArrayList<>();
               }
   
               // 根据组织机构数据范围的上级组织,用于展示完整的树形结构
               //Set<Long> allLevelParentIdsByOrganizations = this.findAllLevelParentIdsByOrganizations(dataScope);
               // 拼接查询条件
               //queryWrapper.in(HrOrganization::getOrgId, allLevelParentIdsByOrganizations);
           }
   
           return this.list(queryWrapper);
       }
       
       @Override
       public List<OrganizationTreeNode> organizationTree(HrOrganizationRequest hrOrganizationRequest) {
   
           // 定义返回结果
           List<OrganizationTreeNode> treeNodeList = CollectionUtil.newArrayList();
           // 组装节点
           List<HrOrganization> hrOrganizationList = this.findListByDataScope(hrOrganizationRequest);
           // 最上层的父ID设置为-1
           int pidsLen = -1;
           HrOrganization p= null;
           for (HrOrganization hrOrganization : hrOrganizationList) {
               if(pidsLen == -1 || pidsLen > hrOrganization.getOrgPids().getBytes().length){
                   pidsLen = hrOrganization.getOrgPids().getBytes().length;
                   p = hrOrganization;
               }
           }
           if(p != null){
               p.setOrgParentId(-1l);
               p.setOrgPids("[-1],");
           }
           for (HrOrganization hrOrganization : hrOrganizationList) {
               OrganizationTreeNode treeNode = OrganizationFactory.parseOrganizationTreeNode(hrOrganization);
               treeNodeList.add(treeNode);
           }
           // 设置树节点上,用户绑定的组织机构数据范围
           if (hrOrganizationRequest.getUserId() != null) {
               List<Long> orgIds = userServiceApi.getUserBindDataScope(hrOrganizationRequest.getUserId());
               if (ObjectUtil.isNotEmpty(orgIds)) {
                   for (OrganizationTreeNode organizationTreeNode : treeNodeList) {
                       for (Long orgId : orgIds) {
                           if (organizationTreeNode.getId().equals(orgId)) {
                               organizationTreeNode.setSelected(true);
                           }
                       }
                   }
               }
           }
           // 构建树并返回
           return new DefaultTreeBuildFactory<OrganizationTreeNode>().doTreeBuild(treeNodeList);
       }
       
       /**
            * 创建组织架构的通用条件查询wrapper
            *
            * @author fengshuonan
            * @date 2020/11/6 10:16
            */
           private LambdaQueryWrapper<HrOrganization> createWrapper(HrOrganizationRequest hrOrganizationRequest) {
               LambdaQueryWrapper<HrOrganization> queryWrapper = new LambdaQueryWrapper<>();
       
               // 查询未删除状态的
               queryWrapper.eq(HrOrganization::getDelFlag, YesOrNotEnum.N.getCode());
       
               // 根据排序升序排列,序号越小越在前
               queryWrapper.orderByAsc(HrOrganization::getOrgSort);
       
               if (ObjectUtil.isEmpty(hrOrganizationRequest)) {
                   return queryWrapper;
               }
       
               String orgName = hrOrganizationRequest.getOrgName();
               String orgCode = hrOrganizationRequest.getOrgCode();
               Long orgParentId = hrOrganizationRequest.getOrgParentId();
               Long orgId = hrOrganizationRequest.getOrgId();
       
               // 拼接组织机构名称条件
               queryWrapper.like(ObjectUtil.isNotEmpty(orgName), HrOrganization::getOrgName, orgName);
       
               // 拼接组织机构编码条件
               queryWrapper.eq(ObjectUtil.isNotEmpty(orgCode), HrOrganization::getOrgCode, orgCode);
       
               // 拼接父机构id查询条件
               if (ObjectUtil.isNotEmpty(orgParentId)) {
                   queryWrapper.and(qw -> {
                       qw.eq(HrOrganization::getOrgId, orgParentId).or().like(HrOrganization::getOrgPids, orgParentId);
                   });
               }
       
               // 拼接机构id查询条件
               queryWrapper.eq(ObjectUtil.isNotEmpty(orgId), HrOrganization::getOrgId, orgId);
       
               if(hrOrganizationRequest.getOrgId() != null){
                   queryWrapper.inSql(HrOrganization::getOrgId,"select org_id from hr_organization where org_pids  like '%"+hrOrganizationRequest.getOrgId()+"%' or org_id = "+hrOrganizationRequest.getOrgId());
               }
               if(hrOrganizationRequest.getDataScopeUserIds() != null){
                   queryWrapper.in(HrOrganization::getCreateUser,hrOrganizationRequest.getDataScopeUserIds());
               }
               if(hrOrganizationRequest.getDataScopeOrganizationIds() != null){
                   queryWrapper.in(HrOrganization::getOrgId,hrOrganizationRequest.getDataScopeOrganizationIds());
               }
               return queryWrapper;
           }
  1. 修改 SysUserController

1). 增加成员

    @Resource
    private SessionManagerApi sessionManagerApi;

2).增加访问权限赋值 DataScopePropertyUtil.setDataScopParam(hrOrganizationRequest,sessionManagerApi);

    /**
     * 查询系统用户
     *
     * @author luojie
     * @date 2020/11/6 13:49
     */
    @GetResource(name = "系统用户_查询", path = "/sysUser/page",responseClass = SysUserDTO.class)
    public ResponseData page(SysUserRequest sysUserRequest) {
        DataScopePropertyUtil.setDataScopParam(sysUserRequest,sessionManagerApi);
        return new SuccessResponseData(sysUserService.findPage(sysUserRequest));
    }
  1. 修改SysUserMapper.mapper
    SysUserMapper.xml
<!--用户列表 oracle版本-->
    <!--用户列表sql-->
        <sql id="user_list_mysql">
            select
            suser.user_id as userId,
            suser.account as account,
            suser.nick_name as nickName,
            suser.real_name as realName,
            suser.avatar as avatar,
            suser.birthday as birthday,
            suser.sex as sex,
            suser.email as email,
            suser.phone as phone,
            suser.tel as tel,
            suser.status_flag as statusFlag,
            suorg.org_id as orgId,
            suorg.position_id as positionId,
            hpos.position_name as positionName
            from sys_user suser
            left join sys_user_org suorg on suser.user_id = suorg.user_id
            left join hr_position hpos on suorg.position_id = hpos.position_id
            <where>
                <if test="sysUserRequest.realName != null and sysUserRequest.realName != ''">
                    and suser.real_name like concat('%',#{sysUserRequest.realName},'%')
                </if>
                <if test="sysUserRequest.account != null and sysUserRequest.account != ''">
                    and suser.account like concat('%',#{sysUserRequest.account},'%')
                </if>
                <if test="sysUserRequest.statusFlag != null and sysUserRequest.statusFlag != ''">
                    and suser.status_flag like concat('%',#{sysUserRequest.statusFlag},'%')
                </if>
                <if test="sysUserRequest.orgId != null and sysUserRequest.orgId != ''">
                    and suorg.org_id in (select org_id from hr_organization where org_pids like CONCAT('%$[',#{sysUserRequest.orgId},'$]%') escape '$' or org_id=#{sysUserRequest.orgId} )
                </if>
                <if test="sysUserRequest.dataScopeUserIds != null and sysUserRequest.dataScopeUserIds != ''">
                    and suser.user_id in
                    <foreach collection="sysUserRequest.dataScopeUserIds" open="(" separator="," close=")" item="item">
                        ${item}
                    </foreach>
                </if>
                <if test="sysUserRequest.dataScopeOrganizationIds != null and sysUserRequest.dataScopeOrganizationIds != ''">
                    and suorg.org_id in
                    <foreach collection="sysUserRequest.dataScopeOrganizationIds" open="(" separator="," close=")" item="item">
                        ${item}
                    </foreach>
                </if>
                and suser.del_flag = 'N'
                order by suser.create_time desc
            </where>
        </sql>
    
        <!--用户列表 oracle版本-->
        <sql id="user_list_oracle">
            select
            suser.user_id as userId,
            suser.account as account,
            suser.nick_name as nickName,
            suser.real_name as realName,
            suser.avatar as avatar,
            suser.birthday as birthday,
            suser.sex as sex,
            suser.email as email,
            suser.phone as phone,
            suser.tel as tel,
            suser.status_flag as statusFlag,
            suorg.org_id as orgId,
            suorg.position_id as positionId,
            hpos.position_name as positionName
            from sys_user suser
            left join sys_user_org suorg on suser.user_id = suorg.user_id
            left join hr_position hpos on suorg.position_id = hpos.position_id
            <where>
                <if test="sysUserRequest.realName != null and sysUserRequest.realName != ''">
                    and suser.real_name  like '%' || #{sysUserRequest.realName} || '%'
                </if>
                <if test="sysUserRequest.account != null and sysUserRequest.account != ''">
                    and suser.account  like '%' || #{sysUserRequest.account} || '%'
                </if>
                <if test="sysUserRequest.statusFlag != null and sysUserRequest.statusFlag != ''">
                    and suser.status_flag  like '%' || #{sysUserRequest.statusFlag} || '%'
                </if>
                <if test="sysUserRequest.orgId != null and sysUserRequest.orgId != ''">
                    and suorg.org_id in(select org_id from hr_organization where org_pids  like '%' || #{sysUserRequest.orgId} || '%' or org_id = #{sysUserRequest.orgId})
                </if>
                <if test="sysUserRequest.dataScopeUserIds != null and sysUserRequest.dataScopeUserIds != ''">
                    and suser.user_id in
                    <foreach collection="sysUserRequest.dataScopeUserIds" open="(" separator="," close=")" item="item">
                        ${item}
                    </foreach>
                </if>
                <if test="sysUserRequest.dataScopeOrganizationIds != null and sysUserRequest.dataScopeOrganizationIds != ''">
                    and suorg.org_id in
                    <foreach collection="sysUserRequest.dataScopeOrganizationIds" open="(" separator="," close=")" item="item">
                        ${item}
                    </foreach>
                </if>
                and suser.del_flag = 'N'
                order by suser.create_time desc
            </where>
        </sql>
  1. 其他自定义业务内容处理步骤.
    1).在request增加数据权限相关属性
    2).controller中进行权限值赋值
    3).service 或者mapper中查询语句拼接修改.

guns的官网地址为:[https://www.stylefeng.cn/]

Guns-Separation是Guns后台管理系统的前后端分离版本,项目采用前后端分离架构,代码简洁,功能丰富,开箱即用,开创快速开发平台新趋势。 Guns-Separation功能介绍: 1、主控面板:控制台页面,可进行工作台,分析页,统计等功能的展示。 2、用户管理:对企业用户和系统管理员用户的维护,可绑定用户职务,机构,角色,数据权限等。 3、应用管理:通过应用来控制不同维度的菜单展示。 4、机构管理:公司组织架构维护,支持多层级结构的树形结构。 5、职位管理:用户职务管理,职务可作为用户的一个标签,职务目前没有和权限等其他功能挂钩。 6、菜单管理:菜单目录,菜单,和按钮的维护是权限控制的基本单位。 7、角色管理:角色绑定菜单后,可限制相关角色的人员登录系统的功能范围。角色也可以绑定数据授权范围。 8、字典管理:系统内各种枚举类型的维护。 9、访问日志:用户的登录和退出日志的查看和管理。 10、操作日志:用户的操作业务的日志的查看和管理。 11、服务监控:服务器的运行状态,Java虚拟机信息,jvm等数据的查看。 12、在线用户:当前系统在线用户的查看。 13、数据监控:druid控制台功能,可查看sql的运行信息。 14、公告管理:系统的公告的管理。 15、文件管理:文件的上传下载查看等操作,文件可使用本地存储,阿里云oss,腾讯cos接入,支持拓展。 16、定时任务:定时任务的维护,通过cron表达式控制任务的执行频率。 17、系统配置:系统运行的参数的维护,参数的配置与系统运行机制息息相关。 18、邮件发送:发送邮件功能。 19、短信发送:短信发送功能,可使用阿里云sms,腾讯云sms,支持拓展。 Guns-Separation快速开始 准备以下环境: 1、npm,jdk1.8,maven 3.6或以上版本。 2、需要准备一个mysql 5.7数据库。 3、您的IDE需要安装lombok插件。 前端运行: 1、cd _web/ 2、npm install 3、npm run serve 后端运行: 1、将数据库文件_sql/guns-separation.sql导入到数据库 2、修改guns-main/src/main/resources/application-local.yml文件,修改为您的数据库ip,账号和密码 3、运行guns-main/src/main/java/cn/stylefeng/guns/GunsApplication类,即可启动后端程序 框架优势: 1、模块化架构设计,层次清晰,业务层推荐写到单独模块,方便升级。 2、前后端分离架构,分离开发,分离部署,前后端互不影响。 3、前端技术采用vue + antdv + axios。 4、后端采用spring boot + mybatis-plus + hutool等,开源可靠。 5、基于spring security(jwt) + 用户UUID双重认证。 6、基于AOP实现的接口粒度的鉴权,最细粒度过滤权限资源。 7、基于hibernate validator实现的校验框架,支持自定义校验注解。 8、提供Request-No的响应header快速定位线上异常问题。 9、在线用户可查,可在线踢人,同账号登录可同时在线,可单独在线(通过系统参数配置)。 10、支持前端 + 后端在线代码生成(后续开放)。 11、支持jenkins一键部署,另自带docker maven插件,支持docker部署。 12、文件,短信,缓存,邮件等,利用接口封装,方便拓展。 13、文件默认使用本地文件,短信默认使用阿里云sms,缓存默认使用内存缓存。 14、文档齐全,持续更新,视频教程将发布到Bilibili(后续开放)。 演示账号密码:superAdmin/123456 Guns-Separation v1.1更新内容: 1、增加上传图片的预览功能 2、完善数据范围分配时候的判断逻辑 3、授权数据取消父级子级关联 4、【前端】工作台界面使用静态数据、环境显示抽屉默认设置为全显示 5、统一日志打印格式 6、修复邮件发送异常的问题 7、修复菜单遍历没有修改子应用的问题 8、默认去掉oss,cos,短信的依赖包,减少了默认打包体积 9、【pr合并】修改密码加密方式为bcrypt 10、修复定位bug
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值