精华内容
下载资源
问答
  • 数据权限-数据列权限设计方案
    千次阅读
    2021-02-28 15:17:36

    前言

    项目实践中,基本都会有权限的需求,权限需求分为两大块:1、功能权限;2、数据权限。而数据权限又可在行和列上细分为两块,即数据范围权限:用户能看到哪些行的记录;数据字段权限:用户能看到这些行对应的哪些字段。本文以字段权限为例做一个demo展示。

    方案

    字段权限方案也有很多种,这里采用配置无权限字段,在sql查询前,对sql进行拦截过滤,剔除无权限字段。

    框架

    这里采用mybatis作为ORM框架。

    配置

    配置pom依赖

    org.mybatis.spring.boot

    mybatis-spring-boot-starter

    2.0.0

    com.github.jsqlparser

    jsqlparser

    1.2

    yml配置

    spring:

    proifles: dev

    #据源配置

    datasource:

    name: test

    url: jdbc:mysql://xxx:3306/xxx?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai

    username: root

    password: xxx

    # 使用druid数据源

    type: com.alibaba.druid.pool.DruidDataSource

    driver-class-name: com.mysql.jdbc.Driver

    # 注意:一定要对应mapper映射xml文件的所在路径

    mybatis:

    mapper-locations: classpath:mybatis/mapper/*.xml

    #注意:对应实体类的路径

    type-aliases-package: com.xxx.model

    #mybatis 配置路径

    config-location: classpath:mybatis/mybatis-config.xml

    plugin配置

    配置mybatis-config.xml

    /p>

    "http://mybatis.org/dtd/mybatis-3-config.dtd">

    插件实现

    import java.lang.reflect.Field;

    import java.util.ArrayList;

    import java.util.Iterator;

    import java.util.List;

    import java.util.Properties;

    import org.apache.ibatis.executor.Executor;

    import org.apache.ibatis.mapping.BoundSql;

    import org.apache.ibatis.mapping.MappedStatement;

    import org.apache.ibatis.plugin.Interceptor;

    import org.apache.ibatis.plugin.Intercepts;

    import org.apache.ibatis.plugin.Invocation;

    import org.apache.ibatis.plugin.Plugin;

    import org.apache.ibatis.plugin.Signature;

    import org.apache.ibatis.session.ResultHandler;

    import org.apache.ibatis.session.RowBounds;

    import net.sf.jsqlparser.JSQLParserException;

    import net.sf.jsqlparser.parser.CCJSqlParserUtil;

    import net.sf.jsqlparser.statement.Statement;

    import net.sf.jsqlparser.statement.Statements;

    import net.sf.jsqlparser.statement.select.PlainSelect;

    import net.sf.jsqlparser.statement.select.Select;

    import net.sf.jsqlparser.statement.select.SelectBody;

    import net.sf.jsqlparser.statement.select.SelectExpressionItem;

    import net.sf.jsqlparser.statement.select.SelectItem;

    //指定连接的方法

    @Intercepts(@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,

    RowBounds.class, ResultHandler.class }))

    public class DataAuthorInterceptor implements Interceptor {

    private Properties properties;

    @Override

    public Object intercept(Invocation invocation) throws Throwable {

    final Object[] args = invocation.getArgs();

    MappedStatement ms = (MappedStatement)args[0];

    Object parameterObject = args[1];

    BoundSql boundSql = ms.getBoundSql(parameterObject);

    //获取初始sql

    String originSql = boundSql.getSql();

    //修改sql

    String changeSql = parseSql(originSql);

    Field field = boundSql.getClass().getDeclaredField("sql");

    field.setAccessible(true);

    field.set(boundSql, changeSql);

    return invocation.proceed();

    }

    //解析SQL,根据数据权限,去除没有权限的字段

    private String parseSql(String sql) {

    List blockList = getBlockCols();

    StringBuffer newSql = new StringBuffer();

    try {

    //解析sql 获得结构化statement

    Statements s = CCJSqlParserUtil.parseStatements(sql);

    //对每一个statement

    for(Statement st : s.getStatements()) {

    if(null != st) {

    //查询sql处理

    if(st instanceof Select) {

    SelectBody selectBody = ((Select) st).getSelectBody();

    if(selectBody instanceof PlainSelect) {

    Iterator it = ((PlainSelect) selectBody).getSelectItems().iterator();

    //遍历查询字段

    while(it.hasNext()) {

    SelectItem si = it.next();

    if(si instanceof SelectExpressionItem) {

    for(String str : blockList) {

    //查询字段同 权限隐藏字段匹配 则从查询中移除

    if(si.toString().contains(str)) {

    it.remove();

    }

    }

    }

    }

    }

    //return ((Select) st).getSelectBody().toString();

    }

    newSql.append(st + ";");

    }

    }

    } catch (JSQLParserException e) {

    e.printStackTrace();

    }

    return newSql.toString();

    }

    //解析sql结构体

    private List getBlockCols(){

    List l = new ArrayList();

    l.add("a");

    l.add("b1");

    return l;

    }

    @Override

    public Object plugin(Object target) {

    return Plugin.wrap(target, this);

    }

    @Override

    public void setProperties(Properties properties) {

    this.properties = properties;

    }

    public static void main(String[] args) {

    String sql = "select a, b, c from table1";

    String sql2 = "select a, b, c from (select e as a, f as b, g as c from table1)";

    String sql3 = "select a as a1, b b1, c from table3 as t3, (select e as a, f as b from table1) , (select g as c from table2)";

    String sql4 = "select c.vin8, (select auto_brand from vin_base b where b.vin8 = c.vin8)\n" +

    "from vin_base c where c.vin8 = '72753413' ";

    String sql5 = "select a, b from table1 union select c, d from table2;";

    String changeSql = new DataAuthorInterceptor().parseSql(sql5);

    System.out.println("changeSql>>>>>>>>" + changeSql);

    }

    }

    到这里,完成了对sql的拦截修改。

    总结

    1、配置:pom.xml依赖配置、yaml应用配置、插件配置、插件实现。

    2、以上示例仅对一般查询及子查询做了处理,对与union查询,需要再实现。

    拦截处理,是一种很好的设计思路,可以对相同处理方式进行组件化,并在应用中,避免侵入式,从而做到润物无声。

    本文地址:https://blog.csdn.net/weixin_42005602/article/details/107151625

    如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

    更多相关内容
  • 从零开始java数据权限篇:数据权限

    千次阅读 2019-09-09 11:59:05
    一:数据权限的产生 二:数据权限的数据切割 1.数据对应的层级图 2.用户数据查询 3.用户流程管理 4.部门-岗位-公司查询拓扑图 三.说明 一:数据权限的产生 在一个后管系统中,由2个最重要的权限划分。第一...

    目录

    一:数据权限的产生

    二:数据权限的数据切割

    1.数据对应的层级图

    2.用户数据查询

    3.用户流程管理

    4.部门-岗位-公司查询拓扑图

    三.说明



    一:数据权限的产生

      在一个后管系统中,由2个最重要的权限划分。第一个访问权限,通过控制访问路径、请求来控制访问的权限,第二个是数据权限,通过一系列的分割策略来对用户进行管理。

     访问权限,可以这么说访问权限可以通过集成框架(比如shiro或者Spring seurity或者oauth2)来控制。所以严格意义上来说访问权限是一个技术框架

     数据权限,数据权限用来对用户信息进行管理包括但是不限于用户列表查询、子母公司数据划分以及工作流等的一系列。但是一个比较尴尬的问题就是,数据权限实则是一个业务层,它是由具体的公司业务来决定的。当然,凡是可以抽象出来的我们都可以抽象出来。目前主流的的数据权限控制以 部门-岗位-上级-本级 这样一个递减结构来做通用式的管理。

      也翻看了一些所谓的数据级权限中间件比如目前介绍较多的Ralasafe,实则上就是在访问Sql上做一些侵入式Sql限制。基于此,我们完全可以在项目中使用AOP做。但是很尴尬的是目前这个数据级的中间件已经停止维护。

     

    二:数据权限的数据切割

      在上面,我们谈到一般都是以 部门-岗位-上级-本级 的结构来做数据权限控制。但是一般项目中会把上级-本级合并产生一个简单的结构:部门-岗位-用户 来维护数据权限。

    1.数据对应的层级图

                                                   

      首先:部门对于用户而言,是用户固有的一个属性,只能是一对一关系。

                  岗位对于用户而言 ,是由上级或者管理员分配的一个属性,可以是一对多(即一个用户被指向多个部门的负责人,但是

                                                        他本身只有某一个部门的属性)。

                  部门对岗位而言,同时也是一对多的关系,即一个部门有多个角色。

    2.用户数据查询

                   

     然后,我们针对组织结构细分:

     (1)公司结构以及部门结构:管理层级(具有本部门的最高权限)以及一般员工(只有自我查询权限)

                                                           其中总公司的管理层具有整个结构的最高权限。

    (2)单个单位中的结构:单个单位内的负责人具有最高单位权限

                                                  单个单位的次级负责人具有管理名下的权限。(即上级-下级的管理权限)

                                                   单个单位内的普通员工只具有自身的权限

    3.用户流程管理

      由于后期要整合工作流,因此这里我们将流程梳理清晰。

     

    4.部门-岗位-公司查询拓扑图

    目前,主要角色分为以下几个:

    (1)普通员工(仅能看到自己的信息)

    (2)部门管理人(仅能看到本部门)

    (3)分公司董事(除了董事会部门的其他分公司所有的部门)

    (4)分公司总负责人(看到分公司所有的信息)

    (5)总公司董事会(除了总公司董事会之外的所有总,自公司的所有部门)

    (6)总董事

    部门-岗位-董事表拓扑(比较简单,就不做UML了)

    据图查询:

    (1)普通员工:这个就不用说了

    (2)部门负责人:查询 用户表中 部门id一样的即可

    (3)分公司董事会:第一步,根据用户表中的部门id去查询部门表

                                          第二步:根据部门表中的所有上级id,取出公司统一的开头(一般第一位为总公司id,第二位为

                                                          分公司id,第三位包括以后是部门层级一级一级玩下的id,以逗号隔开)

                                         第三步:根据公司统一的开头曲模糊查询所有的部门id(这里在程序中控制得当,是完全可以的)

                                         第四步:根据上一步的部门id,同时去掉本身的部门id(即董事会部门的id),然后反查用户表

     (4)分公司负责人 :在上一个的第四步,不去掉本身的部门id

     (5)总公司董事会:查询所有的,除了自身的部门id

    (6)总公司负责人:全查

    (7)自定义:选择部门,然后插入  岗位-部门表做联查(对,这个表只在这里用到)

    三.说明

      上面所描述的是通常情况下,一般都是根据具体业务做管理

     

     

    展开全文
  • 主要介绍了Java如何利用Mybatis进行数据权限控制详解,数据权限控制最终的效果是会要求在同一个数据请求方法中,根据不同的权限返回不同的数据集,而且无需并且不能由研发编码控制。,需要的朋友可以参考下
  • shiro权限框架,数据库mysql,框架用的是springmvc+mybatis+maven部署直接可用
  • JAVA 数据权限设计

    万次阅读 2014-07-17 09:34:18
    在各种系统中,要保证数据对象的安全性以及易操作性,使企业的各业务部门、职能部门能够方便而且高效的协同工作,那么一个好的数据权限管理设计就成为一个关键的问题。虽然企业中各个单元的工作流程有所不同,处理的...

    数据权限设计

    序言

            在各种系统中,要保证数据对象的安全性以及易操作性,使企业的各业务部门、职能部门能够方便而且高效的协同工作,那么一个好的数据权限管理设计就成为一个关键的问题。虽然企业中各个单元的工作流程有所不同,处理的数据对象也有所不同,但是在组织结构、信息的处理方式上具有很多相同的地方,这就为设计数据对象的权限控制提供了一个抽象基础。数据权限的控制不同于一般的功能权限的控制,一般的功能权限指的是某个用户、角色或者是某个用户组能不能操作某种功能。而数据权限指的是某个用户、角色或者是某个用户组对某个数据对象的操作幅度的问题,比如说用户A可以对数据对象进行完全控制,而用户B则只能对数据对象进行浏览的权限,同时数据权限控制隶属于动态权限控制的范畴。

    数据权限设计

            在当前的许多应用程序中都会涉及到权限管理,权限主要分为功能权限和数据权限,至于功能权限相对简单些,网上也有不少的实现方案,这里不再介绍,下边主要探讨下数据权限的设计方案。

            数据权限跟功能权限有很大的不同,颗粒度很小,贯穿于整个项目的开发周期中,无法像功能权限一样在项目要结尾的时候追加,也有一些公司有自己的权限组件(功能权限),给已完成的项目配上权限组件就生效了。数据权限做不到组件级别,必须在项目设计阶段就已经规划好。之前看网上同样有人想基于SPRING切面的原理去实现数据权限,这样就可以做到了低侵入、低耦合,想法很好,可是现实很骨感,这样做使整个应用系统效率大减折扣,同样对数据权限的控制策略也很不灵活。

            下边提出自己的设计方案,在系统中独立一个数据权限模块,该模块可以根据当前业务模块的SQL、当前操作人信息、当前权限的策略来自动生成对应的带数据权限的SQL语句给业务模块继续处理,如下图所示:


    数据权限设计分析

    SQL语句可扩展

            数据权限往往作为功能权限的高级行为,可以从数据对象的幅度方面进行控制,比如用户只能看自己的订单、普通会员看不到某数据对象的高级属性(字段)等等。颗粒度这么细的情况下对结果集处理显然是不可能了,这时只能介入到SQL语句中了,此时又不想在开发阶段让开发人员过多的考虑数据权限的问题,这时最好把SQL语句给提到一个配置文件中,或者数据库中,开发阶段只需开发人员通过数据权限模块的接口调用得到已实现数据权限控制的SQL语句,这样也算做到的代码的低侵入。

    SQL语句高效解析处理

            数据权限模块的核心之一就有SQL语句的高效解析处理,SQL处理指根据当前登录人信息及数据权限策略生成一个带有数据权限处理结果的SQL语句,所以这里对SQL语句的解析处理必须要求精确、准确。在开发阶段由开发人员把SQL写入到配置文件中,在运行阶段由数据权限取得该SQL进行分析处理(加上数据权限),这样就完成了SQL的组装处理。

    数据权限策略设计

            最核心的地方就是数据权限策略的设计了,这里先引入几个概念:

    1、资源:数据权限的控制对象,业务系统中的各种资源。比如订单单据、销售单等

    2、主体:用户、部门、角色等

    3、规则:用于【数据权限】的条件规则 

    这里侧重分析下主体及规则,主体有层级关系,可以为不同主体设置不同规则,比如:当前数据仅对创建人(或者某个人)有效、下级主体的权限对于上级主体同样有效(可配置,如可勾选)、非当前主体只能看到部分数据(部分数据可选)。这里只提供部分规则示例,现实环境中需要根据企业环境或者项目环境去完善这些规则。

    数据权限策略优化

            数据权限同样属于权限范畴,每次访问都会去请求验证权限,所以权限的认证必须要高效,这时可以写算法或者是用MEMCACHE等来提高响应速度。

    展开全文
  • Java利用Mybatis进行数据权限控制

    千次阅读 2019-06-06 18:19:18
    权限控制主要分为两块,认证(Authentication)与授权(Authorization)。认证之后确认了身份正确,业务系统就会进行授权,现在业界比较流行的模型就是RBAC(Role-Based Access Control)。RBAC包含为下面四个要素:...

    权限控制主要分为两块,认证(Authentication)与授权(Authorization)。认证之后确认了身份正确,业务系统就会进行授权,现在业界比较流行的模型就是RBAC(Role-Based Access Control)。RBAC包含为下面四个要素:用户、角色、权限、资源。用户是源头,资源是目标,用户绑定至角色,资源与权限关联,最终将角色与权限关联,就形成了比较完整灵活的权限控制模型。
    资源是最终需要控制的标的物,但是我们在一个业务系统中要将哪些元素作为待控制的资源呢?我将系统中待控制的资源分为三类:

    1. URL访问资源(接口以及网页)
    2. 界面元素资源(增删改查导入导出的按钮,重要的业务数据展示与否等)
    3. 数据资源

    现在业内普遍的实现方案实际上很粗放,就是单纯的“菜单控制”,通过菜单显示与否来达到控制权限的目的。
    我仔细分析过,现在大家做的平台分为To C和To B两种:

    1. To C一般不会有太多的复杂权限控制,甚至大部分连菜单控制都不用,全部都可以访问。
    2. To B一般都不是开放的,只要做好认证关口,能够进入系统的只有内部员工。大部分企业内部的员工互联网知识有限,而且作为内部员工不敢对系统进行破坏性的尝试。

    所以针对现在的情况,考虑成本与产出,大部分设计者也不愿意在权限上进行太多的研发力量。
    菜单和界面元素一般都是由前端编码配合存储数据实现,URL访问资源的控制也有一些框架比如SpringSecurity,Shiro。
    目前我还没有找到过数据权限控制的框架或者方法,所以自己整理了一份。

    数据权限控制原理

    数据权限控制最终的效果是会要求在同一个数据请求方法中,根据不同的权限返回不同的数据集,而且无需并且不能由研发编码控制。这样大家的第一想法应该就是AOP,拦截所有的底层方法,加入过滤条件。这样的方式兼容性较强,但是复杂程度也会更高。我们这套系统中,采用的是利用Mybatis的plugin机制,在底层SQL解析时替换增加过滤条件。
    这样一套控制机制存在很明显的优缺点,首先缺点:

    1. 适用性有限,基于底层的Mybatis。
    2. 方言有限,针对了某种数据库(我们使用Mysql),而且由于需要在底层解析处理条件所以有可能造成不同的数据库不能兼容。当然Redis和NoSQL也无法限制。

    当然,假如你现在就用Mybatis,而且数据库使用的是Mysql,这方面就没有太大影响了。

    接下来说说优点:

    1. 减少了接口数量及接口复杂度。原本针对不同的角色,可能会区分不同的接口或者在接口实现时利用流程控制逻辑来区分不同的条件。有了数据权限控制,代码中只用写基本逻辑,权限过滤由底层机制自动处理。
    2. 提高了数据权限控制的灵活性。例如原本只有主管能查本部门下组织架构/订单数据,现在新增助理角色,能够查询本部门下组织架构,不能查询订单。这样的话普通的写法就需要调整逻辑控制,使用数据权限控制的话,直接修改配置就好。

    数据权限实现

    上一节就提及了实现原理,是基于Mybatis的plugins(查看官方文档)实现。

    MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
    Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
    ParameterHandler (getParameterObject, setParameters)
    ResultSetHandler (handleResultSets, handleOutputParameters)
    StatementHandler (prepare, parameterize, batch, update, query)

    Mybatis的插件机制目前比较出名的实现应该就是PageHelper项目了,在做这个实现的时候也参考了PageHelper项目的实现方式。所以权限控制插件的类命名为PermissionHelper。
    机制是依托于Mybatis的plugins机制,实际SQL处理的时候基于jsqlparser这个包。
    设计中包含两个类,一个是保存角色与权限的实体类命名为PermissionRule,一个是根据实体变更底层SQL语句的主体方法类PermissionHelper。

    首先来看下PermissionRule的结构:

    public class PermissionRule {
    
        private static final Log log = LogFactory.getLog(PermissionRule.class);
        /**
         * codeName<br>
         * 适用角色列表<br>
         * 格式如: ,RoleA,RoleB,
         */
        private String roles;
        /**
         * codeValue<br>
         * 主实体,多表联合
         * 格式如: ,SystemCode,User,
         */
        private String fromEntity;
        /**
         * codeDesc<br>
         * 过滤表达式字段, <br>
         * <code>{uid}</code>会自动替换为当前用户的userId<br>
         * <code>{me}</code> main entity 主实体名称
         * <code>{me.a}</code> main entity alias 主实体别名
         * 格式如:
         * <ul>
         * <li>userId = {uid}</li>
         * <li>(userId = {uid} AND authType > 3)</li>
         * <li>((userId = {uid} AND authType) > 3 OR (dept in (select dept from depts where manager.id = {uid})))</li>
         * </ul>
         */
        private String exps;
    
        /**
         * codeShowName<br>
         * 规则说明
         */
        private String ruleComment;
    
    }
    

    看完这个结构,基本能够理解设计的思路了。数据结构中保存如下几个字段:

    • 角色列表:需要使用此规则的角色,可以多个,使用英文逗号隔开。
    • 实体列表:对应的规则应用的实体(这里指的是表结构中的表名,可能你的实体是驼峰而数据库是蛇形,所以这里要放蛇形那个),可以多个,使用英文逗号隔开。
    • 表达式:表达式就是数据权限控制的核心了。简单的说这里的表达式就是一段SQL语句,其中设置了一些可替换值,底层会用对应运行时的变量替换对应内容,从而达到增加条件的效果。
    • 规则说明:单纯的一个说明字段。

    核心流程
    系统启动时,首先从数据库加载出所有的规则。底层利用插件机制来拦截所有的查询语句,进入查询拦截方法后,首先根据当前用户的权限列表筛选出PermissionRule列表,然后循环列表中的规则,对语句中符合实体列表的表进行条件增加,最终生成处理后的SQL语句,退出拦截器,Mybatis执行处理后SQL并返回结果。

    讲完PermissionRule,再来看看PermissionHelper,首先是头:

    @Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
            @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
    public class PermissionHelper implements Interceptor {
    }
    

    头部只是标准的Mybatis拦截器写法,注解中的Signature决定了你的代码对哪些方法拦截,update实际上针对**修改(Update)、删除(Delete)生效,query是对查询(Select)**生效。

    下面给出针对Select注入查询条件限制的完整代码:

    
        private String processSelectSql(String sql, List<PermissionRule> rules, UserDefaultZimpl principal) {
            try {
                String replaceSql = null;
                Select select = (Select) CCJSqlParserUtil.parse(sql);
                PlainSelect selectBody = (PlainSelect) select.getSelectBody();
                String mainTable = null;
                if (selectBody.getFromItem() instanceof Table) {
                    mainTable = ((Table) selectBody.getFromItem()).getName().replace("`", "");
                } else if (selectBody.getFromItem() instanceof SubSelect) {
                    replaceSql = processSelectSql(((SubSelect) selectBody.getFromItem()).getSelectBody().toString(), rules, principal);
                }
                if (!ValidUtil.isEmpty(replaceSql)) {
                    sql = sql.replace(((SubSelect) selectBody.getFromItem()).getSelectBody().toString(), replaceSql);
                }
                String mainTableAlias = mainTable;
                try {
                    mainTableAlias = selectBody.getFromItem().getAlias().getName();
                } catch (Exception e) {
                    log.debug("当前sql中, " + mainTable + " 没有设置别名");
                }
    
    
                String condExpr = null;
                PermissionRule realRuls = null;
                for (PermissionRule rule :
                        rules) {
                    for (Object roleStr :
                            principal.getRoles()) {
                        if (rule.getRoles().indexOf("," + roleStr + ",") != -1) {
                            if (rule.getFromEntity().indexOf("," + mainTable + ",") != -1) {
                                // 若主表匹配规则主体,则直接使用本规则
                                realRuls = rule;
    
                                condExpr = rule.getExps().replace("{uid}", UserDefaultUtil.getUserId().toString()).replace("{bid}", UserDefaultUtil.getBusinessId().toString()).replace("{me}", mainTable).replace("{me.a}", mainTableAlias);
                                if (selectBody.getWhere() == null) {
                                    selectBody.setWhere(CCJSqlParserUtil.parseCondExpression(condExpr));
                                } else {
                                    AndExpression and = new AndExpression(selectBody.getWhere(), CCJSqlParserUtil.parseCondExpression(condExpr));
                                    selectBody.setWhere(and);
                                }
                            }
    
                            try {
                                String joinTable = null;
                                String joinTableAlias = null;
                                for (Join j :
                                        selectBody.getJoins()) {
                                    if (rule.getFromEntity().indexOf("," + ((Table) j.getRightItem()).getName() + ",") != -1) {
                                        // 当主表不能匹配时,匹配所有join,使用符合条件的第一个表的规则。
                                        realRuls = rule;
                                        joinTable = ((Table) j.getRightItem()).getName();
                                        joinTableAlias = j.getRightItem().getAlias().getName();
    
                                        condExpr = rule.getExps().replace("{uid}", UserDefaultUtil.getUserId().toString()).replace("{bid}", UserDefaultUtil.getBusinessId().toString()).replace("{me}", joinTable).replace("{me.a}", joinTableAlias);
                                        if (j.getOnExpression() == null) {
                                            j.setOnExpression(CCJSqlParserUtil.parseCondExpression(condExpr));
                                        } else {
                                            AndExpression and = new AndExpression(j.getOnExpression(), CCJSqlParserUtil.parseCondExpression(condExpr));
                                            j.setOnExpression(and);
                                        }
                                    }
                                }
                            } catch (Exception e) {
                                log.debug("当前sql没有join的部分!");
                            }
                        }
                    }
                }
                if (realRuls == null) return sql; // 没有合适规则直接退出。
    
                if (sql.indexOf("limit ?,?") != -1 && select.toString().indexOf("LIMIT ? OFFSET ?") != -1) {
                    sql = select.toString().replace("LIMIT ? OFFSET ?", "limit ?,?");
                } else {
                    sql = select.toString();
                }
    
            } catch (JSQLParserException e) {
                log.error("change sql error .", e);
            }
            return sql;
        }
    

    重点思路
    重点其实就在于Sql的解析和条件注入,使用开源项目JSqlParser

    • 解析出MainTable和JoinTable。from之后跟着的称为MainTable,join之后跟着的称为JoinTable。这两个就是我们PermissionRule需要匹配的表名,PermissionRule::fromEntity字段。
    • 解析出MainTable的where和JoinTable的on后面的条件。使用and连接原本的条件和待注入的条件,PermissionRule::exps字段。
    • 使用当前登录的用户信息(放在缓存中),替换条件表达式中的值。
    • 某些情况需要忽略权限,可以考虑使用ThreadLocal(单机)/Redis(集群)来控制。

    结束语

    想要达到无感知的数据权限控制,只有机制控制这么一条路。本文选择的是通过底层拦截Sql语句,并且针对对应表注入条件语句这么一种做法。应该是非常经济的做法,只是基于文本处理,不会给系统带来太大的负担,而且能够达到理想中的效果。大家也可以提出其他的见解和思路。

    展开全文
  • 通用数据权限的思考与设计

    千次阅读 2021-02-27 10:00:44
    1、数据权限概述1.1、什么是数据权限?如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:787707172,群里有阿里大牛直播讲解技术,以及Java...
  • 做到代码低侵入度,在开发时不需要太多关注数据权限控制,可以在应用开发完成后,通过对表和视图定义权限控制策略,然后绑定到登录用户或功能URI上来进行数据权限控制。数据访问控制需要调整时,只需要修改定义的...
  • java用户角色权限设计

    热门讨论 2012-12-20 11:50:51
    java用户角色权限设计,很不错哦,可以看看
  • 数据权限设计(转载)

    千次阅读 2021-03-13 08:52:05
    一、前言几乎在任何一个系统中,都离不开权限的设计,权限设计 = 功能权限 + 数据权限,而功能权限,在业界常常是基于RBAC(Role-Based Access Control)的一套方案。而数据权限,则根据不同的业务场景,则权限却不尽...
  • 关于数据库表字段的数据权限设计

    千次阅读 2021-03-11 17:15:59
    吐槽:刚在同事的帮忙下,把maven工程成功导入到eclipse,期间遇到的最大问题就是安装eclipse插件,花费了其中大部分的时间现在做的研发产品,遇到的一个新的需求是“控制外部系统对于表中字段的访问权限”,其实...
  • java如何做权限管理

    千次阅读 2021-03-01 08:44:13
    如图:根据用户角色取出该角色所有权限,并对用户进行权限分配;注意菜单的按钮(新增、删除、修改)权限是放在中间表(user_menu)中的;1、新增用户时,是要根据用户角色进行分配权限的一定记得批量添加;批量、批量、...
  • java系统权限设计思路总结

    千次阅读 2018-09-30 22:36:02
    这篇文章的定位,不是宣传某个框架,仅仅之是...1.什么是权限,程序员理解的权限和客户所理解的权限是不是一致的。 2.权限的划分原则,权限到底是根据什么原则进行组合的。 3.角色是用户与权限之间的必要的关...
  • java用户角色权限数据库设计

    千次阅读 2015-11-29 19:41:30
    为了实现需求,数据库的设计可谓及其重要,无论是“组”操作的概念,还是整套权限管理系统的重用性,都在于数据库的设计。 我们先来分析一下数据库结构: 首先,action表(以下简称为“权限表”),...
  • JAVA后台权限管理系统

    千次阅读 2020-08-19 08:55:52
    一款 Java 语言基于 SpringBoot2.x、Layui、Thymeleaf、MybatisPlus、Shiro、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发...
  • Java实现权限管理的两种方式

    千次阅读 2021-03-13 07:49:19
    //,必须要登录// 取得当前用户;User manager = (User) HttpUtils.getAdminUserSession(req);// 检查管理用户是否登录if (manager == null) {resp.sendRedirect(req....}//第二,必须在权限定义范围内if(auth_v...
  • 求J2ee数据权限的设计思路,基本要求: 部门经理可以查看该部门下的所有数据对象(比如销售订单),销售人员只可以查看自己的销售订单或者查看其他人的销售订单(通过权限设置),请问该怎么设计?求高人帮忙.
  • 本系统采用了 B/S 体系结构,以 MySql 作为数据库管理数据,以 JSP 作为前端开发语音,采用当前最流行的 SSM 框架(Spring+SpringMVC+MyBatis),标准的 MVC 模式,将整个系统划分为表现层,controller 层,service ...
  • 通用数据权限的设计思路

    万次阅读 热门讨论 2020-01-02 09:25:30
    根据目前的调研情况,有两种数据级别权限设计思路,都可以实现对人员访问的数据权限控制,从而实现不同的人员能够看到不同的数据,例如经理能够看到其部门下所有人的数据,而单个的员工只能看到自己的数据。...
  • java权限管理框架有哪些?

    千次阅读 2021-03-21 09:51:25
    要想学好java知识,就一定要将java知识熟练运用,每个知识点都不可以放过...它能够轻松处理 登录控制、URL权限控制和(业务级)数据权限管理,实现权限与业务分离。Ralasafe是一款开箱即用的中间件,XML配置和JAVA编...
  • 基于SpringAOP实现数据权限控制

    万次阅读 热门讨论 2018-01-05 19:24:14
    基于SpringAOP实现数据权限控制 在此主要是实现对用户查询数据返回字段的控制。比如一个表格有A,B,C,D,E五列,用户U1只能查看A,B,C三列。 此文章讲述的内容并不能实现在查询时仅查询A,B,C三列,而是在查询...
  • 一般来说,权限有许多种,我们经常用到的一般有操作权限和数据权限两种。 功能权限 所谓操作权限就是有或者没有做某种操作的权限,具体表现形式就是你看不到某个菜单或按钮,当然也有的是把菜单或按钮灰掉的形式。...
  • 数据权限设计研究-行数据权限

    万次阅读 多人点赞 2019-01-17 19:22:56
    数据权限设计研究-行数据权限关于权限设计功能权限数据权限前提数据分类几种场景设计方案与思路映射表提供过滤sql的方法测试实际应用查询新增修改删除修改数据的私有,公开,部门属性私有改为部门私有改为公开部门改...
  • 权限管理框架属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则用户可以访问而且只能访问自己被授权的资源,那么java权限框架有几种?今天我们就来给大家讲解一下常见的权限框架。1.Shiro 框架...
  • Java权限设计与控制

    万次阅读 多人点赞 2017-06-17 10:53:34
    1.场景还原 近期,由于项目中要引用权限模块,于是笔者趁着空暇时间写了一个权限控制的小Demo,现在跟大伙讲讲权限的原理。2.权限数据库设计user:用户表user_role:用户角色表(用户跟角色多对多关系)role:角色表role...
  • java权限控制

    热门讨论 2012-02-02 00:05:50
    历史上最全的java权限控制 基础S2SH的,基于servlet的,基于spring的,基于struts2的,很多,...有角色权限,角色组,数据权限,操作权限,查询权限,菜单权限,按钮权限控制,粗粒度的,细粒度的,很多,欢迎下载....
  • java权限管理与用户角色权限设计

    万次阅读 多人点赞 2018-06-16 00:14:28
    java权限管理与用户角色权限设计2016年10月29日 19:24:41阅读数:12545实现业务系统中的用户权限管理 B/S系统中的权限比C/S中的更显的重要,C/S系统因为具有特殊的客户端,所以访问用户的权限检测可以通过客户端...
  • 本文章记录使用spring-boot结合mybatis实现简单的数据权限控制,前端逻辑不做概述,主要实现逻辑是使用mybatis自带的方法获取执行的SQL,然后根据存储的数据权限方案拼接where条件,最后拼接到待执行的SQL后面实现...
  • Java Web权限管理设计及实现

    万次阅读 多人点赞 2018-01-28 13:37:51
    最近在做一个权限相关的功能,在项目原有权限管理上面进行扩展,一方面支持界面上控制到按钮级别,后端接口没有权限不能进行访问;另一个方面,对项目中应用管理模块的应用管理员授权,使其具有对其名下的应用添加...
  • 详解Java之路(五) 访问权限控制

    千次阅读 2021-02-12 21:50:58
    Java中,所有事物都具有某种形式的访问权限控制。访问权限的控制等级从最大到最小依次为:public,protected,包访问权限(无关键词)和private。public,protected和private这几个Java访问权限修饰词在使用时,是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 479,049
精华内容 191,619
关键字:

java 数据权限

java 订阅