精华内容
下载资源
问答
  • 今天研究了下 若依的数据权限,还是很有收获,尤其从全县管理的思路上。 其基本实现思路是通过注解的方式,把需要权限通知的部分在注解中提前拼接好,当使用的时候根据注解中传入的 参数决定控制的权限范围。 过程...

    今天研究了下 若依的数据权限,还是很有收获,尤其从权限管理的实现思路上。
    其基本实现思路是通过注解的方式,把需要权限通知的部分在注解中提前拼接好,当使用的时候根据注解中传入的 参数决定控制的权限范围。
    过程大致如下
    一、自定义注解
    在这里插入图片描述

    二、通通过切面方式来处理需要进行权限管理的方法
    在这里插入图片描述

    三、需要进行权限控制的方法
    在这里插入图片描述

    四、把aspect拦截加工好的sql在mybatis中进行处理 ,已达到数据权限控制的目的
    在这里插入图片描述

    ps: 第四部的params.dataScope 这个怎么来的?
    所有对象都集成了一个基类:BaseEntity;该类中有个map类型属性params,具体值是在aspect中进行加工而成。这样mybatis中就能读取到该参数了。
    在这里插入图片描述

    展开全文
  • 文章目录权限分类数据权限实现MyBatis的拦截器简介具体实现数据库设计权限类型设计拦截器实现参数传递加载拦截器忽略拦截使用示例 今天来整理分享下常用的权限设计,以及基于Mybatis-plus实现的一套数据权限的实现。...


    权限管理是我们日常开发中很重要的一个点, 功能权限的实现大部分比较重而且业界也比较统一了,我这边就不详细介绍了,分享下一个基于Mybatis-plus实现的一套 数据权限方案。

    权限分类

    • 功能权限:能看到什么功能模块,能操作什么功能,增删改查实体等。(常见
    • 数据权限:能看到哪些数据,例如管理员能看到所有人的数据,普通员工只能看到自己的数据,领导能看到本部门的数据。(常见
    • 字段权限:能看到哪些字段,例如普通员工看不到自己剩余的请假天数,领导和管理员可以。(不常见

    功能权限:管理类系统常用的权限控制方式基于角色为基础设计(RBAC,Role-Based Access Control),主要由用户,角色,权限(资源)三个实体;用户角色关系,角色权限关系两个中间关联控制,有很多轮子,基本都是基于Spring Security 、Shiro或自定义AOP实现的,我这里仅介绍常用的数据权限的实现。

    数据权限:我看了下目前的主流实现有2中方式:

    • 方案1.基于AOP+自定义注解,在service层进行拦截处理

    • 方案2.基于mybatis拦截器+自定义注解,在mapper层处理

      我这里的持久层框架选型为:mybatis-plus

    针对这2种实现方式,其内部原理都是在原始sql上拼接 create_by= xxx And create_dept_id in xxx ,然后替换待执行的原始sql。

    我个人更偏向于第二种方案,因为就像分页插件一样,数据权限过滤本来就是针对某一个sql进行过滤,这是在持久层应该做的事情。后面的实现逻辑也都是参照分页插件,利用mybatis拦截器的插件机制实现。

    数据权限实现

    MyBatis的拦截器简介

    在Mybatis框架中,已经给我们提供了拦截器接口org.apache.ibatis.plugin.Interceptor,防止我们改动源码来添加行为实现拦截。说到拦截器,不得不提一下,拦截器是通过动态代理对Mybatis加入一些自己的行为。

    Interceptor接口中包含3个方法如下:

    public interface Interceptor {
      Object intercept(Invocation invocation) throws Throwable;
      default Object plugin(Object target) {
        return Plugin.wrap(target, this);
      }
      default void setProperties(Properties properties) {
        // NOP
      }
    }
    
    • intercepter方法是拦截的核心方法,方法参数invocation可以对拦截对象进行修改。
    • plugin方法用于生成被拦截的对象的代理,方法参数target是原始对象。
    • setProperties方法用于获取配置intercepter时的参数。

    MyBatis插件的实现必须继承Interceptor接口并实现其中的intercept拦截方法,除此之外,拦截器还需要定义拦截的对象以及方法,如下所示。

    img

    • @Intercepts定义它是个拦截器
    • @Signature标注拦截的对象(type属性),方法名(method属性)及方法参数(args属性)。
      • type属性可以是MyBatis执行过程的四种对象。
      • method用于标注对象中的某个具体方法。
      • args是方法的参数类型。

    MyBatis执行过程的四种对象

    type类型作用
    Executor调度执行StatementHandler、ParmmeterHandler、ResultHandler执行相应的SQL语句
    StatementHandler执行SQL的过程,作为最常用的插件拦截对象
    ParameterHandler设置预编译参数用的
    ResultHandler处理结果集

    对数据权限的拦截实际也是对执行的SQL进行修改,所以拦截的方法签名可等同于分页拦截器。此处需注意分页拦截器需要在数据权限拦截器之后执行。

    具体实现

    本来准备完全参照分页插件PaginationInnerInterceptor.java性能分析插件PerformanceInterceptor.java去实现的,但在阅读源码时发现了一个插件DataPermissionInterceptor.java,有趣的是在官网并没有发现对其的任何介绍,从注释来看,其实现的功能就是数据权限过滤。后面就直接使用它来实现了。

    数据库设计

    在需要进行权限过滤的表,新增2个字段create_by(该记录由谁创建),create_dept_id(该记录由哪个部门创建)。

    暂不考虑人员换部门或者假定人员换部门但是数据归属还是之前的部门

    权限类型设计

    • 查看全部数据 - where 1=1
    • 查看本人所在组织机构数据 - where create_dept_id = userDeptId
    • 查看本人数据 - where create_by = userId and create_dept_id = userDeptId
    • 查看自定义组织机构数据 - where create_dept_id in (deptIds)
    • 查看自定义sql过滤 - where 1=1 and 自定义过滤sql
    @Getter
    @AllArgsConstructor
    public enum DataFilterTypeEnum {
        ALL(1, "全部"),
        DEPT(2, "本人所在组织机构"),
        SELF(3, "本人"),
        DEPT_SETS(4, "自定义组织机构"),
        DIY(5, "自定义sql过滤");
        int type;
        String desc;
    }
    

    拦截器实现

    DataPermissionInterceptor.java中留了个扩展的口子DataPermissionHandler.java,我们只需要实现DataPermissionHandler接口,并按照业务规则处理SQL,就可以实现数据权限的功能。

    其中用到了JSqlParser,JSqlParser是一个SQL语句解析器,它将SQL转换为Java类的可遍历层次结构。mybatis-plus中也引入了JSqlParser包。

    @Slf4j
    public class LakerDataPermissionHandler implements DataPermissionHandler {
    
        /**
         * @param where             原SQL Where 条件表达式
         * @param mappedStatementId Mapper接口方法ID
         * @return
         */
        @SneakyThrows
        @Override
        public Expression getSqlSegment(Expression where, String mappedStatementId) {
    
            // 1. 获取权限过滤相关信息
            DataFilterMetaData dataFilterMetaData = DataFilterThreadLocal.get();
            try {
                log.debug("开始进行权限过滤,dataFilterMetaData:{} , where: {},mappedStatementId: {}", dataFilterMetaData, where, mappedStatementId);
                if (dataFilterMetaData == null) {
                    return where;
                }
                Expression expression = new HexValue(" 1 = 1 ");
                if (where == null) {
                    where = expression;
                }
                switch (dataFilterMetaData.filterType) {
                    // 查看全部
                    case ALL:
                        return where;
                    // 查看本人所在组织机构以及下属机构
                    case DEPT_SETS:
                        // 创建IN 表达式
                        // 创建IN范围的元素集合
                        Set<Long> deptIds = dataFilterMetaData.getDeptIds();
                        // 把集合转变为JSQLParser需要的元素列表
                        ItemsList itemsList = new ExpressionList(deptIds.stream().map(LongValue::new).collect(Collectors.toList()));
                        InExpression inExpression = new InExpression(new Column("create_dept_id"), itemsList);
                        return new AndExpression(where, inExpression);
                    // 查看当前部门的数据
                    case DEPT:
                        //  = 表达式
                        // dept_id = deptId
                        EqualsTo equalsTo = new EqualsTo();
                        equalsTo.setLeftExpression(new Column("create_dept_id"));
                        equalsTo.setRightExpression(new LongValue(dataFilterMetaData.getDeptId()));
                        // 创建 AND 表达式 拼接Where 和 = 表达式
                        // WHERE xxx AND dept_id = 3
                        return new AndExpression(where, equalsTo);
                    // 查看自己的数据
                    case SELF:
                        // create_by = userId
                        EqualsTo selfEqualsTo = new EqualsTo();
                        selfEqualsTo.setLeftExpression(new Column("create_by"));
                        selfEqualsTo.setRightExpression(new LongValue(dataFilterMetaData.getUserId()));
                        return new AndExpression(where, selfEqualsTo);
                    case DIY:
                        return new AndExpression(where, new StringValue(dataFilterMetaData.getSql()));
                    default:
                        break;
                }
            } catch (Exception e) {
                log.error("LakerDataPermissionHandler.err", e);
            } finally {
                DataFilterThreadLocal.clear();
            }
            return where;
        }
    }
    

    参数传递

    我们这里肯定要配合用户权限去做过滤的,但是方法参数中没办法传递参数,这里我们借助ThreadLocal去实现,注意使用完毕后要调用clear

    @Slf4j
    public class DataFilterThreadLocal {
        private static final ThreadLocal<DataFilterMetaData> ThreadLocalDataFilter = new ThreadLocal<>();
        public static void clear() {
            ThreadLocalDataFilter.remove();
        }
        public static void set(DataFilterMetaData metaData) {
            ThreadLocalDataFilter.set(metaData);
        }
        public static DataFilterMetaData get() {
            return ThreadLocalDataFilter.get();
        }
    }
    

    加载拦截器

    @Configuration
    @MapperScan("com.laker.map.*.mapper")
    public class MybatisConfig {
        @Bean
    	public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    
            // 添加数据权限插件
            DataPermissionInterceptor dataPermissionInterceptor = new DataPermissionInterceptor();
            LakerDataPermissionHandler lakerDataPermissionHandler = new LakerDataPermissionHandler();
            // 添加自定义的数据权限处理器
            dataPermissionInterceptor.setDataPermissionHandler(lakerDataPermissionHandler);
            interceptor.addInnerInterceptor(dataPermissionInterceptor);
    
            // 分页插件
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            return interceptor;
        }
    
    

    注意要在分页插件之前添加。

    忽略拦截

    mybatis-plus内置了@InterceptorIgnore注解。其内置插件的一些过滤规则

    • 支持注解在 Mapper 上以及 Mapper.Method 上 同时存在则 Mapper.method 比 Mapper 优先级高
    • 支持: true 和 false , 1 和 0 , on 和 off
    • 各属性返回 true 表示不走插件(在配置了插件的情况下,不填则默认表示 false)
    @InterceptorIgnore(dataPermission = "1")
    @Select("select  * from resource_service_area ")
    Page<ServiceArea> selectAll(Page page);
    

    使用示例

      @Test
        public void testDataFilter() {
            // 模拟设置当前用户的id是123,其拥有的数据权限为:本人
            DataFilterThreadLocal.set(DataFilterMetaData.builder().filterType(DataFilterTypeEnum.SELF).userId(123L).build());
            Page<ServiceArea> page = new Page<>();
            Page<ServiceArea> page1 = serviceAreaMapper.selectAll(page);
            System.out.println(JSONUtil.toJsonStr(page1));
        }
    

    这里验证了与分页插件一起使用,这也是我们非常常用的功能了。执行过程如下:

    sql1:

    ID:com.laker.map.resource.mapper.ServiceAreaMapper.selectAll_mpCount
    Execute SQLSELECT
            COUNT(*) 
        FROM
            resource_service_area 
        WHERE
            1 = 1 
            AND create_by = 123
    

    自动拼接了 WHERE 1 = 1 AND create_by = 123

    sql2:

    ID:com.laker.map.resource.mapper.ServiceAreaMapper.selectAll
    Execute SQLSELECT
            * 
        FROM
            resource_service_area 
        WHERE
            1 = 1 
            AND create_by = 123 LIMIT 10
    

    自动拼接了 WHERE 1 = 1 AND create_by = 123

    结果

    {
        "hitCount": false,
        "optimizeCountSql": true,
        "records": [
            {
                "address": "怀远县",
                "areaName": "君王服务区",
                "id": 26
            },
            {
                "address": "肥西县",
                "areaName": "丰乐服务区",
                "id": 27
            }
            xxx
        ],
        "total": 529,
        "current": 1,
        "size": 10,
        "orders": [
        ],
        "isSearchCount": true
    }
    

    参考:

    • https://blog.csdn.net/qq_29653517/article/details/86299928

    • https://blog.csdn.net/qq_43437874/article/details/114691376

    • https://pagehelper.github.io/docs/interceptor/

    • 动态数据权限的设计


    🍎QQ群【837324215】
    🍎关注我的公众号【Java大厂面试官】,一起学习呗🍎🍎🍎

    展开全文
  • Java实现权限管理的两种方式

    千次阅读 2021-03-06 04:21:59
    编辑特别推荐:种方式:利用filter、xml文件和用户信息表配合使用来实现权限管理。1.过滤器filterpackage cn.com.aaa.bbb.filter;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;...

    编辑特别推荐:

    种方式:利用filter、xml文件和用户信息表配合使用来实现权限管理。

    1.过滤器filter

    package cn.com.aaa.bbb.filter;

    import java.io.IOException;

    import java.io.InputStream;

    import java.util.HashMap;

    import java.util.Iterator;

    import java.util.List;

    import java.util.Map;

    import javax.servlet.Filter;

    import javax.servlet.FilterChain;

    import javax.servlet.FilterConfig;

    import javax.servlet.ServletContext;

    import javax.servlet.ServletException;

    import javax.servlet.ServletRequest;

    import javax.servlet.ServletResponse;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.dom4j.Document;

    import org.dom4j.Element;

    import org.dom4j.io.SAXReader;

    import cn.com.aaa.bbb.domain.User;

    import cn.com.aaa.bbb.util.HttpUtils;

    /**

    * 过滤:后台管理的模块授权。根据:配置文件xml,根据当前session中用的管理员信息。

    * 注:不用再访问数据库。也不需要再使用什么 bean 去判断。直接在这个类里就可以判断。

    * @author cuiguangqiang

    *

    */

    public class ManagerAuthFilter implements Filter {

    protected static final Log logger = LogFactory.getLog(ManagerAuthFilter.class);

    public static final String MAPPING_FILE = "/WEB-INF/managerauthmapping.xml";

    private ServletContext context = null;

    private Map actions = new HashMap();

    public void init(FilterConfig filterConfig) throws ServletException {

    context = filterConfig.getServletContext();

    if(context==null){

    logger.error("unable to init as servlet context is null");

    return;

    }

    loadConf();

    logger.info("ManagerAuthFilter configure success.");

    }

    private void loadConf() {

    InputStream inputStream = context.getResourceAsStream(MAPPING_FILE);

    if (inputStream == null) {

    logger.info("unable find auth mapping file " + MAPPING_FILE);

    } else {

    actions = parseConf(inputStream);

    }

    }

    private Map parseConf(InputStream inputStream) {

    try {

    SAXReader reader = new SAXReader();

    Document document = reader.read(inputStream);

    return createActionMap(document);

    } catch (Exception e) {

    logger.info(e.getMessage());

    e.printStackTrace();

    }

    return new HashMap();

    }

    private Map createActionMap(Document document) {

    Map map = new HashMap();

    Element root = document.getRootElement();

    //处理XML,读入JAVA Object对象中。

    List actionList = root.elements();

    for (Iterator it = actionList.iterator(); it.hasNext();) {

    Element e = (Element) it.next();

    String actionName = e.attributeValue("name");

    String auth_value = e.element("auth-value").getTextTrim();

    map.put(actionName,auth_value);

    logger.info(actionName + " is " + auth_value);

    }

    return map;

    }

    public void doFilter(ServletRequest request, ServletResponse response,

    FilterChain chain) throws IOException, ServletException {

    //处理某次提交的Action,是否在权限定义范围内

    //权限共有:1:站长;2:编辑;0:Admin ; all 代表所有人都可以。(均需要登录)

    HttpServletRequest req = (HttpServletRequest) request;

    HttpServletResponse resp = (HttpServletResponse) response;

    //(1)得到此次用户的提交请求

    String url = req.getServletPath();

    //(2)只有在配置文件中存在的 action 才进行处理

    String method = req.getParameter("method");

    if(method!=null){

    url = url + "?method=" + method;

    }

    String auth_value = (String)actions.get(url);

    if(auth_value==null){

    logger.info("action is not in Manager Auth xml.");

    chain.doFilter(request, response);

    return;

    }

    来源:考试大-Java认证

    责编:xxm  评论 纠错

    上一页1

    展开全文
  • Mybatis-Plus通过注解形式实现数据权限过滤

    千次阅读 热门讨论 2021-07-21 15:46:26
    本文借鉴若依快速开发框架的数据权限思路,通过注解形式实现数据权限过滤,优点是灵活方便。 代码 创建注解类 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ...

    背景

    本文借鉴若依快速开发框架的数据权限思路,通过注解形式实现数据权限过滤,优点是灵活方便。

    代码

    创建注解类

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface DataScope {
    
        /**
         * 部门表的别名
         */
        public String deptAlias() default "";
    
        /**
         * 部门字段名
         */
        String deptField() default "dept_id";
    }
    

    创建DataScopePermissionHandler 处理器(重点)

    @Aspect
    @Slf4j
    @Component
    public class DataScopePermissionHandler implements DataPermissionHandler {
    
    	/**
         * 通过ThreadLocal记录权限相关的属性值
         */
        ThreadLocal<DataScopeParam> threadLocal = new ThreadLocal<>();
    
    	/**
         * 清空当前线程上次保存的权限信息
         */
         @After("dataScopePointCut()")
        public void clearThreadLocal(){
            threadLocal.remove();
            log.debug("threadLocal.remove()");
        }
    
    	/**
         * 注解对象
         */
        private DataScope controllerDataScope;
    
        /**
         * 配置织入点
         */
        @Pointcut("@annotation(com.xxx.base.datascope.annotation.DataScope)")
        public void dataScopePointCut() {
        }
    
        @Before("dataScopePointCut()")
        public void doBefore(JoinPoint point) {
            // 获得注解
            controllerDataScope = getAnnotationLog(point);
            if (controllerDataScope != null) {
                // 获取当前的用户及相关属性,需提前获取和保存数据权限对应的部门ID集合
                User currentUser = SecurityUtil.getUser();
                DataScopeParam dataScopeParam = new DataScopeParam(controllerDataScope.deptAlias(),
                        controllerDataScope.deptField(),
                        currentUser.isAdmin(),
                        currentUser.getDataScope());
                threadLocal.set(dataScopeParam);
                log.debug("currentUser.getDataScope() = {}", currentUser.getDataScope());
            }
        }
    
        /**
         * 是否存在注解,如果存在就获取
         */
        private DataScope getAnnotationLog(JoinPoint joinPoint) {
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            Method method = methodSignature.getMethod();
            if (method != null) {
                return method.getAnnotation(DataScope.class);
            }
            return null;
        }
    
        /**
         * @param where             原SQL Where 条件表达式
         * @param mappedStatementId Mapper接口方法ID
         * @return
         */
        @SneakyThrows
        @Override
        public Expression getSqlSegment(Expression where, String mappedStatementId) {
            log.debug("DataScopePermissionHandler .getSqlSegment");
            DataScopeParam dataScopeParam = threadLocal.get();
            if(controllerDataScope == null || dataScopeParam == null || dataScopeParam.isAdmin()){
                return where;
            }
    
            if (where == null) {
                where = new HexValue(" 1 = 1 ");
            }
    
            String deptSql = "".equals(dataScopeParam.deptAlias) ? dataScopeParam.deptField : dataScopeParam.deptAlias + "." + dataScopeParam.deptField;
    
            // 把集合转变为JSQLParser需要的元素列表
            ItemsList itemsList;
            if(CollectionUtils.isEmpty(dataScopeParam.secretary)){
            	//如果权限为空,则只能看自己部门的
                itemsList = new ExpressionList(Collections.singletonList(new LongValue(SecurityUtil.getUser().getOrganizeId())));
            }else {
            	//查看权限内的数据
                itemsList = new ExpressionList(dataScopeParam.secretary.stream().map(LongValue::new).collect(Collectors.toList()));
            }
            InExpression inExpression = new InExpression(new Column(deptSql), itemsList);
            log.debug("where = {}", where);
            log.debug("inExpression = {}", inExpression);
            return new AndExpression(where, inExpression);
    
        }
    
        /**
         * ThreadLocal存储对象
         */
        @Data
        @AllArgsConstructor
        static class DataScopeParam{
            /**
             * 部门表的别名
             */
            private String deptAlias;
    
            /**
             * 部门字段名
             */
            private String deptField;
            
            /**
             * 是否是管理员
             */
            private boolean isAdmin;
    
            /**
             * 数据权限范围
             */
            private Set<Integer> secretary;
        }
    }
    

    将DataScopePermissionHandler处理器添加进Mybatis-Plus配置文件

    @Configuration
    @MapperScan("com.xx.**.mapper*")
    public class MybatisPlusConfig {
    
        @Autowired
        private DataScopePermissionHandler dataScopePermissionHandler;
    
        /**
         * 最新版分页插件
          */
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    
            // 添加数据权限插件
            DataPermissionInterceptor dataPermissionInterceptor = new DataPermissionInterceptor();
            // 添加自定义的数据权限处理器
            dataPermissionInterceptor.setDataPermissionHandler(dataScopePermissionHandler);
            interceptor.addInnerInterceptor(dataPermissionInterceptor);
    
            // 分页插件
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            return interceptor;
        }
    
    }
    

    使用方法

    	@DataScope(deptAlias = "sys_user", deptField = "dept_id")
        @GetMapping("/page")
        public ResultEntity page(){
            Page page = PageUtil.getPageFromRequest();
            return ResultEntity.page(sysUserService.page(page));
        }
    

    效果

    2021-07-21 16:07:30.500 DEBUG 2584 --- [nio-8010-exec-2] c.v.b.d.DataScopePermissionHandler       : currentUser.getDataScope() = [96, 1, 97, 66, 98, 99, 106, 16, 112, 113, 20, 22, 89, 60, 92, 93, 63]
    2021-07-21 16:07:30.596 DEBUG 2584 --- [nio-8010-exec-2] c.v.b.d.DataScopePermissionHandler       : DataScopePermissionHandler.getSqlSegment
    2021-07-21 16:07:30.598 DEBUG 2584 --- [nio-8010-exec-2] c.v.b.d.DataScopePermissionHandler       : where = 1 = 1 
    2021-07-21 16:07:30.598 DEBUG 2584 --- [nio-8010-exec-2] c.v.b.d.DataScopePermissionHandler       : inExpression = o.organize_id IN (96, 1, 97, 66, 98, 99, 106, 16, 112, 113, 20, 22, 89, 60, 92, 93, 63)
    2021-07-21 16:07:30.910 DEBUG 2584 --- [nio-8010-exec-2] c.v.s.mapper.SysUserMapper.page  : ==>  Preparing: SELECT user_id, dept_id, password, username, head_icon, gender FROM sys_user WHERE 1 = 1 AND sys_user.dept IN (96, 1, 97, 66, 98, 99, 106, 16, 112, 113, 20, 22, 89, 60, 92, 93, 63) LIMIT 0, 10
    2021-07-21 16:07:30.931 DEBUG 2584 --- [nio-8010-exec-2] c.v.s.mapper.SysUserMapper.page  : ==> Parameters: 
    2021-07-21 16:07:30.962 DEBUG 2584 --- [nio-8010-exec-2] c.v.s.mapper.SysUserMapper.page  : <==      Total: 10
    2021-07-21 16:07:30.969 DEBUG 2584 --- [nio-8010-exec-2] c.v.b.d.DataScopePermissionHandler       : DataScopePermissionHandler .getSqlSegment
    2021-07-21 16:07:30.969 DEBUG 2584 --- [nio-8010-exec-2] c.v.b.d.DataScopePermissionHandler       : where = 1 = 1 
    2021-07-21 16:07:30.969 DEBUG 2584 --- [nio-8010-exec-2] c.v.b.d.DataScopePermissionHandler       : inExpression = sys_user.dept_id IN (96, 1, 97, 66, 98, 99, 106, 16, 112, 113, 20, 22, 89, 60, 92, 93, 63)
    2021-07-21 16:07:30.969 DEBUG 2584 --- [nio-8010-exec-2] c.v.s.mapper.SysUserMapper.count   : ==>  Preparing: SELECT count(1) FROM sys_user WHERE 1 = 1 AND sys_user.dept_id IN (96, 1, 97, 66, 98, 99, 106, 16, 112, 113, 20, 22, 89, 60, 92, 93, 63)
    2021-07-21 16:07:30.969 DEBUG 2584 --- [nio-8010-exec-2] c.v.s.mapper.SysUserMapper.count   : ==> Parameters: 
    2021-07-21 16:07:30.972 DEBUG 2584 --- [nio-8010-exec-2] c.v.s.mapper.SysUserMapper.count   : <==      Total: 1
    

    拓展

    可根据需要多增加一些过滤条件,实现多种过滤方式

    展开全文
  • SpringCloud 微服务实现数据权限控制

    千次阅读 2021-01-11 10:11:05
    而本章要讲的是权限控制的另一个层面数据权限,意思是控制可访问数据资源的数量。 举个例子: 有一批业务员跟进全国的销售订单。他们被按城市进行划分,一个业务员跟进3个城市的订单,为了保护公司的业务数据不能被...
  • 数据权限设计(转载)

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

    千次阅读 2021-02-27 10:00:44
    1、数据权限概述1.1、什么是数据权限?如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:787707172,群里有阿里大牛直播讲解技术,以及Java...
  • RBAC模型整合数据权限

    千次阅读 2021-03-03 14:48:09
    在项目实际开发中我们不光要控制一个用户能访问哪些资源,还需要控制用户只能访问资源中的某部分数据。控制一个用户能访问哪些资源我们有很成熟的权限管理模型即RBAC,但是控制用户只能访问某部分资...
  • ruoyi关于数据权限的处理

    千次阅读 2021-04-13 19:13:53
    每个表中都需要有字段去关联dept表,取出dept_id,用这个来处理数据权限中部门相关权限 每个表中都需要有字段user_id(默认的为这个字段名),这个用来处理数据权限中本人相关权限 解决方式参考: <sql id=...
  • 权限管理之数据权限(若依框架)

    千次阅读 2021-08-24 15:01:17
    数据权限说明:不同的用户查看到的数据不一样。比如,部门经理可以查看属于该部门的所有数据,该部门普通员工只能查看属于自己的数据。 若依框架使用的策略是: 角色表中通过数据范围字段来控制角色。 数据范围...
  • mybatis-plus统一处理数据权限

    千次阅读 热门讨论 2021-07-14 16:21:42
    问题:项目要求数据权限配置查询,全部、自定义、部门、部门及下级部门、个人。要求做统一处理。 分析: 数据权限精确到个人。那么每张表里面都要有创建人字段。每次插入数据都要保存创建人。查询的时候才能区分。...
  • Vue 实现前端权限控制

    千次阅读 2020-12-19 15:11:43
    权限流程图前言首先我们确定的权限控制分为三大部分,其中根据粒度大小分的更细:登录权限控制页面权限控制菜单中的页面是否可以被访问页面中的按钮 (增、删、改、查)的权限控制是否显示接口权限控制一、登录权限...
  • 若依框架使用数据权限

    千次阅读 2021-07-10 13:32:30
    1.若依架构自带的数据权限为以下几种: 2.再功能模块给用户角色配置对应的数据权限如何让它生效 1)查看自己若依架构的 com.ruoyi.framework.aspectj. DataScopeAspect类 /** * 数据过滤处理 * * @...
  • 1、数据权限处理类HkhjDataPermissionHandler.java package com.pojo.common.core.config; import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler; import ...
  • 实现接口权限验证——验签

    千次阅读 2021-03-20 02:15:12
    实现接口权限验证 开发用户接口实例之前,还需要设计一套严格的接口验证方法,保证 PI 接口的安全 性。常见的接口验证一般包含以下几种 接口时效性验证。为了防止大 的重复请求, 可以设置每次请求的时效 小到以秒...
  • vue 菜单级别权限控制实现

    千次阅读 2021-03-02 09:34:37
    前端菜单权限就是根据根据用户的权限不同控制菜单的显示隐藏,不同的场景,实现方式也有所不同。 一、前端控制路由表 前端配置好路由表,然后根据接口返回权限数据处理成的路由表,然后使用 addRouters 方法添加到...
  • vue实现角色权限控制

    千次阅读 2021-03-16 11:24:25
    下面我们就看一看是如何实现这些个权限控制的。 二、接口访问的权限控制 接口权限就是对用户的校验。正常来说,在用户登录时服务器需要给前台返回一个Token,然后在以后前台每次调用接口时都需要带上这个Token, ...
  • 权限管理 一般指根据系统设置的安全规则或者安全策略,用户可以访问而且只能访问自己被授权的资源,不多不少。权限管理几乎出现在任何系统里面,只要有用户和密码的系统。 分类 DataPermissionInterceptor ...
  • 分享一个通用的数据权限限制SQL自动注入工具(附源码)。
  • vue 按钮级别权限控制实现

    千次阅读 2021-02-04 10:30:22
    总结一下前端对于按钮级别权限的控制方法,根据后端返回的权限数据实现不同权限的用户展示不同的操作按钮。实现方法有两种:定义一个全局方法配合 v-if 指令;自定义指令。 首先,将接口返回的权限数据保存到 ...
  • 《SpringBoot整合SpringSecurity实现权限控制(二):权限数据基本模型设计》 《SpringBoot整合SpringSecurity实现权限控制(三):前端动态装载路由与菜单》 《SpringBoot整合SpringSecurity实现权限控制(四):...
  • 不同用户在看同一模块时可能因为数据权限不同而看到不同的数据,这些是属于数据权限的范畴。 2、功能权限的类别 菜单权限:后台管理系统中的菜单一般由路由定义而成,因此对菜单进行权限管控实际上就是对路由进行...
  • 在这种方式下,需要第三方应用也采用了AD的认证方式才可以正常的和PBI RS做集成。注意,这种方式要求第三方系统采用了AD的认证方式,并且用户在使用AD账户登录了操作系统,才能正常的不用输入登录用户名和密码去访问...
  • 前言 ...菜单权限的话我们可以在后端返回的菜单数据上做处理,后端处理时只将当前用户有权限的菜单数据返给前端即可,前端按数据渲染菜单即可。 按钮权限的话,在 Spring MVC + Freemarker 中,我..
  • java如何做权限管理

    千次阅读 2021-03-01 08:44:13
    如图:根据用户角色取出该角色所有权限,并对用户进行权限分配;注意菜单的按钮(新增、删除、修改)权限是放在中间表(user_menu)中的;1、新增用户时,是要根据用户角色进行分配权限的一定记得批量添加;批量、批量、...
  • Android 10 中身体活动数据的隐私保护

    千次阅读 2020-12-20 17:16:17
    Google Fit是我们在 2015 年推出的一个开放式平台。通过调用平台内置的 Google Fit API,开发者可以为应用添加...Android 10 在数据可控性方面又作了进一步优化,提高了用户对此类个人数据的控制权,而其中的一项关...
  • Linux下SFTP用户权限设置条件及实现命令众所周知SFTP账号是基于SSH账号的,所以在默认情况下访问服务器的权限是非常大的,今天的教程就是教大家进行SFTP用户权限设置。必要条件:你的openssh-server版本至少得失4.8...
  • 大数据是工业社会的「自由」资源,谁掌握了数据,谁就掌握了主动权。随着企业数字化转型的浪潮,数据更是成为了金融行业的核心资产和创新要素。 而证券行业作为国家金融活动的重要入口,汇聚了大量的金融数据。其...
  • PostgreSQL 数据安全之数据加密

    千次阅读 2021-09-01 10:23:17
    PostgreSQL 支持多个不同级别的灵活加密技术,包括密码加密、字段加密、存储加密、传输加密、认证加密以及应用加密,可以保护数据不因数据库服务器被盗、内部管理员或者不安全的网络传输而导致泄露。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 820,260
精华内容 328,104
关键字:

数据权限的实现方式