SpringCloud 微服务数据权限控制的实现

目录
  • 一、 整体架构
  • 二、 实现流程
  • 三、 实现步骤
    • 1. 注解实现
    • 2. 注解使用
    • 3. 实现AuthStoreSupplier
    • 4. 实现AuthQuerySupplier
    • 5. 开启数据权限
  • 四、 综述
  • 五、源代码

举个例子:

有一批业务员跟进全国的销售订单。他们被按城市进行划分,一个业务员跟进3个城市的订单,为了保护公司的业务数据不能被所有人都掌握,故每个业务员只能看到自己负责城市的订单数据。所以从系统来讲每个业务员都有访问销售订单的功能,然后再需要配置每个业务员负责的城市,以此对订单数据进行筛选。

要实现此功能有很多方法,如果系统中多个地方都需要类似的需求,那我们就可以将其提出来做成一个通用的功能。这里我介绍一个相对简单的解决方案,以供参考。

一、 整体架构

数据权限为作一个注解的形式挂在每一个需要数据权限控制的Controller上,由于和具体的程序逻辑有关故有一定的入侵性,且需要数据库配合使用。

二、 实现流程

1.浏览器传带查询权限范围参数访问Controller,如cities

POST http://127.0.0.1:8000/order/query
accept: */*
Content-Type: application/json
token: 1e2b2298-8274-4599-a26f-a799167cc82f

{"cities":["cq","cd","bj"],"userName":"string"}

2.通过注解拦截权限范围参数,并根据预授权范围比较,回写在授权范围内的权限范围参数

cities = ["cq","cd"]

3.通过参数传递到DAO层,在SQL语句中拼装出查询条件,实现数据的过滤

select * from order where city in ('cq','cd')

三、 实现步骤

1. 注解实现

注解的完整代码,请详见源代码

1)创建注解

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface ScopeAuth {

    String token() default "AUTH_TOKEN";
    String scope() default "";
    String[] scopes() default {};
}

此注解为运行时RetentionPolicy.RUNTIME作用在方法上ElementType.METHOD

token:获取识别唯一用户的标识,与用户数据权限存储有关

scopescopes:预请求的数据权限范围

2) AOP实现注解

public class ScopeAuthAdvice {

    @Around("@annotation(scopeAuth)")
    public Object before(ProceedingJoinPoint thisJoinPoint, ScopeAuth scopeAuth) throws Throwable {
        // ... 省略过程
        // 获取token
        String authToken = getToken(args, scopeAuth.token(), methodSignature.getMethod());
            // 回写范围参数
        setScope(scopeAuth.scope(), methodSignature, args, authToken);

        return thisJoinPoint.proceed();
    }

    /**
     * 设置范围
     */
    private void setScope(String scope, MethodSignature methodSignature, Object[] args, String authToken) {
        // 获取请求范围
        Set<String> requestScope = getRequestScope(args, scope, methodSignature.getMethod());
        ScopeAuthAdapter adapter = new ScopeAuthAdapter(supplier);
        // 已授权范围
        Set<String> authorizedScope = adapter.identifyPermissionScope(authToken, requestScope);
        // 回写新范围
        setRequestScope(args, scope, authorizedScope, methodSignature.getMethod());
    }

    /**
     * 回写请求范围
     */
    private void setRequestScope(Object[] args, String scopeName, Collection<String> scopeValues, Method method) {
        // 解析 SPEL 表达式
        if (scopeName.indexOf(SPEL_FLAG) == 0) {
            ParseSPEL.setMethodValue(scopeName, scopeValues, method, args);
        }
    }
}

此为演示代码省略了过程,主要功能为通过token拿到预先授权的数据范围,再与本次请求的范围做交集,最后回写回原参数。

过程中用到了较多的SPEL表达式,用于计算表达式结果,具体请参考ParseSPEL文件

3)权限范围交集计算

public class ScopeAuthAdapter {

    private final AuthQuerySupplier supplier;

    public ScopeAuthAdapter(AuthQuerySupplier supplier) {
        this.supplier = supplier;
    }

    /**
     * 验证权限范围
     * @param token
     * @param requestScope
     * @return
     */
    public Set<String> identifyPermissionScope(String token, Set<String> requestScope) {
        Set<String> authorizeScope = supplier.queryScope(token);

        String ALL_SCOPE = "AUTH_ALL";
        String USER_ALL = "USER_ALL";

        if (authorizeScope == null) {
            return null;
        }

        if (authorizeScope.contains(ALL_SCOPE)) {
            // 如果是全开放则返回请求范围
            return requestScope;
        }

        if (requestScope == null) {
            return null;
        }

        if (requestScope.contains(USER_ALL)){
            // 所有授权的范围
            return authorizeScope;
        }

        // 移除不同的元素
        requestScope.retainAll(authorizeScope);

        return requestScope;
    }
}

此处为了方便设置,有两个关键字范围

  • AUTH_ALL:预设所有范围,全开放的意思,为数据库预先设置值,请求传什么值都通过
  • USER_ALL:请求所有授权的范围,请求时传此值则会以数据库预设值为准

4) spring.factories自动导入类配置

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector=\
  fun.barryhome.cloud.annotation.ScopeAuthAdvice

如果注解功能是单独项目存在,在使用时有可能会存在找不到引入文件的问题,可通过此配置文件自动载入需要初始化的类

2. 注解使用

@ScopeAuth(scopes = {"#orderDTO.cities"}, token = "#request.getHeader(\"X-User-Name\")")
@PostMapping(value = "/query")
public String query(@RequestBody OrderDTO orderDTO, HttpServletRequest request) {
    return Arrays.toString(orderDTO.getCities());
}

在需要使用数据权限的controller方法上增加@ScopeAuth注解

scopes = {"#orderDTO.cities"}:表示取输入参数orderDTO的cities值,这里是表达式必须加#

实际开发过程中,需要将orderDTO.getCities()带入后续逻辑中,在DAO层将此拼装在SQL中,以实现数据过滤功能

3. 实现AuthStoreSupplier

AuthStoreSupplier接口为数据权限的存储接口,与AuthQuerySupplier配合使用,可按实际情况实现

此接口为非必要接口,可由数据库或Redis存储(推荐),一般在登录的同时保存在Redis中

4. 实现AuthQuerySupplier

AuthQuerySupplier接口为数据权限查询接口,可按存储方法进行查询,推荐使用Redis

@Component
public class RedisAuthQuerySupplier implements AuthQuerySupplier {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 查询范围
     */
    @Override
    public Set<String> queryScope(String key) {
        String AUTH_USER_KEY = "auth:logic:user:%s";
        String redisKey = String.format(AUTH_USER_KEY, key);

        List<String> range = redisTemplate.opsForList().range(redisKey, 0, -1);

        if (range != null) {
            return new HashSet<>(range);
        } else {
            return null;
        }
    }
}

在分布式结构里,也可将此实现提出到权限模块,采用远程调用方式,进一步解耦

5. 开启数据权限

@EnableScopeAuth
@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

四、 综述

至此数据权限功能就实现了。在微服务器架构中为了实现功能的复用,将注解的创建和AuthQuerySupplier的实现提取到公共模块中,那么在具体的使用模块就简单得多了。只需增加@ScopeAuth注解,配置好查询方法就可以使用。

五、源代码

文中代码由于篇幅原因有一定省略并不是完整逻辑,如有兴趣请Fork源代码

到此这篇关于SpringCloud 微服务数据权限控制的实现的文章就介绍到这了,更多相关SpringCloud内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springcloud+Mybatis使用多数据源的四种方式(小结)

    前段时间在做会员中心和中间件系统开发时,多次碰到多数据源配置问题,主要用到分包方式.参数化切换.注解+AOP.动态添加 这四种方式.这里做一下总结,分享下使用心得以及踩过的坑. 分包方式 数据源配置文件 在yml中,配置两个数据源,id分别为master和s1. spring: datasource: master: jdbcUrl: jdbc:mysql://192.168.xxx.xxx:xxxx/db1?......... username: xxx password: xxx drive

  • SpringCloud如何使用Eureka实现服务之间的传递数据

    相信大家最关心的肯定不是什么一大堆的破理论,然后还似懂非懂的,最关心得莫过于服务之间的参数传递,数据获取. Ok,今天就告诉大家三种微服务之间传输数据的方式,分别是: 1.最基本的利用Ip端口进行请求访问接口实现数据的传输 2.使用Eureka取代Ip(硬编码)的方式实现数据的传输 3.使用Feign更加快捷"分服务"的方式实现微服务之间的数据传输(对Feign一点不了解的暂时不用理解,就是SpringCloud的组成的一部分后期会进行详细讲解,在此处讲解只是为自己mark一下) 前提

  • springcloud结合bytetcc实现数据强一致性原理解析

    1 使用背景和约束 公司使用的是springcloud,面临分布式事务的场景的时候,可以使用对springcloud支持比较好的byte-tcc框架,git目前2600星,使用起来也非常方便,原理也很清晰,非常适合学习. https://github.com/liuyangmin... ,结合cloud有几个重点约束如下, (1)一个业务接口,需要有三种实现类,分别是try,confirm,cancel,符合tcc的思路.实现方法必须加Transactional,且propagation必须是R

  • SpringCloud 微服务数据权限控制的实现

    目录 一. 整体架构 二. 实现流程 三. 实现步骤 1. 注解实现 2. 注解使用 3. 实现AuthStoreSupplier 4. 实现AuthQuerySupplier 5. 开启数据权限 四. 综述 五.源代码 举个例子: 有一批业务员跟进全国的销售订单.他们被按城市进行划分,一个业务员跟进3个城市的订单,为了保护公司的业务数据不能被所有人都掌握,故每个业务员只能看到自己负责城市的订单数据.所以从系统来讲每个业务员都有访问销售订单的功能,然后再需要配置每个业务员负责的城市,以此对订单数

  • SpringCloud微服务之Hystrix组件实现服务熔断的方法

    一.熔断器简介 微服务架构特点就是多服务,多数据源,支撑系统应用.这样导致微服务之间存在依赖关系.如果其中一个服务故障,可能导致系统宕机,这就是所谓的雪崩效应. 1.服务熔断 微服务架构中某个微服务发生故障时,要快速切断服务,提示用户,后续请求,不调用该服务,直接返回,释放资源,这就是服务熔断. 熔断生效后,会在指定的时间后调用请求来测试依赖是否恢复,依赖的应用恢复后关闭熔断. 2.服务降级 服务器高并发下,压力剧增的时候,根据当业务情况以及流量,对一些服务和页面有策略的降级(可以理解为关闭不必

  • SpringCloud微服务架构实战之微服务治理功能的实现

    微服务治理 Spring Cloud 工具套件为微服务治理提供了全面的技术支持.这些治理工具主要包括服务的注册与发现.负载均衡管理.动态路由.服务降级和故障转移.链路跟踪.服务监控等.微服务治理的主要功能组件如下: 注册管理服务组件Eureka,提供服务注册和发现的功能. 负载均衡服务组件Ribbon,提供负载均衡调度管理的功能. 边缘代理服务组件Zuul,提供网关服务和动态路由的功能. 断路器组件Hystrix,提供容错机制.服务降级.故障转移等功能. 聚合服务事件流组件Turbine,可用来

  • SpringCloud微服务应用config配置中心详解

    目录 前言 一.传统应用配置痛点 二.Config 配置中心介绍 三.服务端Config Server搭建 1.pom依赖 2.application启动类配置 3.application.yml配置 4.test-dev.xml(客户端应读取的配置) 5.项目结构 四.客户端Config Client搭建 1.pom依赖 2.application启动类配置 3.bootstrap.yml配置 4.application.yml配置 5.测试controller 6.项目结构 五.动态刷新 六

  • springcloud微服务之Eureka配置详解

    Eureka注册中心/服务发现框架 Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的.SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能. Eureka包含两个组件:Eureka Server和Eureka Client. Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Serve

  • SpringCloud 微服务最佳开发实践

    现在基于SpringCloud的微服务开发日益流行,网上各种开源项目层出不穷.我们在实际工作中可以参考开源项目实现很多开箱即用的功能,但是必须要遵守一定的约定和规范. 本文结合我们实际的开发中遇到的一些问题整理出了一份微服务开发的实践规范,欢迎各位大佬拍砖指点. Maven规范 1.所有项目必须要有一个统一的parent模块 所有微服务工程都依赖这个parent,parent用于管理依赖版本,maven仓库,jar版本的统一升级维护 在parent下层可以有 core,starter,rate-

  • 基于Pinpoint对SpringCloud微服务项目实现全链路监控的问题

    目录 1.全链路监控的概念 2.pinpoint链路监控组件的介绍 3.使用docker部署pinpoint监控组件 4.在微服务中集成pinpoint-agent 4.1.pinpoint-agent的接入方式 4.2.配置pinpoint-agent 4.3.修改每个微服务程序的Dockerfile接入pinpoint-agent 4.4.先将product商品服务接入到pinpoint观察效果 4.5.将所有的微服务接入到pinpoint系统 5.pinpoint监控系统简单使用 5.1.

  • SpringCloud微服务熔断器Hystrix使用详解

    目录 什么是Hystrix Hystrix实战 总结 什么是Hystrix 在日常生活用电中,如果我们的电路中正确地安置了保险丝,那么在电压异常升高时,保险丝就会熔断以便切断电流,从而起到保护电路安全运行的作用. 在货船中,为了防止漏水和火灾的扩散,一般会将货仓进行分割,避免了一个货仓出事导致整艘船沉没的悲剧,这就是舱壁保护机制. Hystrix提供的熔断器也类似,在调用某个服务提供者时,当一定时间内请求总数超过配置的阈值,且窗口期内错误率过高,那Hystrix就会对调用请求熔断,后续的请求直接

  • SpringCloud微服务开发基于RocketMQ实现分布式事务管理详解

    目录 消息队列实现分布式事务原理 RocketMQ的事务消息 代码实现 基础配置 发送半消息 执行本地事务与回查 Account-Service消费消息 测试 小结 消息队列实现分布式事务原理 首先让我们来看一下基于消息队列实现分布式事务的原理方案. 柔性事务 发送消息的服务有个OUTBOX数据表,在进行INSERT.UPDATE.DELETE 业务操作时也会给OUTBOX数据表INSERT一条消息记录,这样可以保证原子性,因为这是基于本地的ACID事务. OUTBOX表充当临时消息队列,然后我

  • SpringCloud微服务熔断器使用详解

    目录 一.简介 二.作用 三.核心概念 3.1 熔断目的 3.2 降级目的 四.实例 4.1 基于Hystrix 4.1.1 熔断触发降级 4.1.2 超时触发降级 4.1.3 资源隔离触发降级 4.2 基于OpenFeign pom.xml 一.简介 当微服务中的某个子服务,发生异常服务器宕机,其他服务在进行时不能正常访问而一直占用资源导致正常的服务也发生资源不能释放而崩溃,这时为了不造成整个微服务群瘫痪,进行的保护机制 就叫做熔断,是一种降级策略 熔断的目的:保护微服务集群 二.作用 对第三

随机推荐