浅谈Spring Cloud下微服务权限方案

背景

从传统的单体应用转型Spring Cloud的朋友都在问我,Spring Cloud下的微服务权限怎么管?怎么设计比较合理?从大层面讲叫服务权限,往小处拆分,分别为三块:用户认证用户权限服务校验

用户认证

传统的单体应用可能习惯了session的存在,而到了Spring cloud的微服务化后,session虽然可以采取分布式会话来解决,但终究不是上上策。开始有人推行Spring Cloud Security结合很好的OAuth2,后面为了优化OAuth 2中Access Token的存储问题,提高后端服务的可用性和扩展性,有了更好Token验证方式JWT(JSON Web Token)。这里要强调一点的是,OAuth2JWT这两个根本没有可比性,是两个完全不同的东西。
OAuth2是一种授权框架,而JWT是一种认证协议

OAuth2认证框架OAuth2中包含四个角色:

  1. 资源拥有者(Resource Owner)
  2. 资源服务器(Resource Server)
  3. 授权服务器(Authorization Server)
  4. 客户端(Client)

OAuth2包含4种授权模式

  1. 授权码(认证码)模式 (Authorization code)
  2. 简化(隐形)模式 (Impilict
  3. 用户名密码模式 (Resource Owner Password Credential)
  4. 客户端模式 (Client Credential)

其中,OAuth2的运行流程如下图,摘自RFC 6749:

+--------+                +---------------+
|    |--(A)- Authorization Request ->|  Resource  |
|    |                |   Owner   |
|    |<-(B)-- Authorization Grant ---|        |
|    |                +---------------+
|    |
|    |                +---------------+
|    |--(C)-- Authorization Grant -->| Authorization |
| Client |                |   Server  |
|    |<-(D)----- Access Token -------|        |
|    |                +---------------+
|    |
|    |                +---------------+
|    |--(E)----- Access Token ------>|  Resource  |
|    |                |   Server  |
|    |<-(F)--- Protected Resource ---|        |
+--------+                +---------------+

我们在Spring Cloud OAuth2中,所有访问微服务资源的请求都在Http Header中携带Token,被访问的服务接下来再去请求授权服务器验证Token的有效性,目前这种方式,我们需要两次或者更多次的请求,所有的Token有效性校验都落在的授权服务器上,对于我们系统的水平扩展成为一个非常大的瓶颈。

JWT认证协议

授权服务器将用户信息和授权范围序列化后放入一个JSON字符串,然后使用Base64进行编码,最终在授权服务器用私钥对这个字符串进行签名,得到一个JSON Web Token

假设其他所有的资源服务器都将持有一个RSA公钥,当资源服务器接收到这个在Http Header中存有Token的请求,资源服务器就可以拿到这个Token,并验证它是否使用正确的私钥签名(是否经过授权服务器签名,也就是验签)。验签通过,反序列化后就拿到Toekn中包含的有效验证信息。

其中,主体运作流程图如下:

+-----------+                   +-------------+
|      |    1-Request Authorization    |       |
|      |------------------------------------>|       |
|      |   grant_type&username&password  |       |--+
|      |                   |Authorization| | 2-Gen
|      |                   |Service   | |  JWT
|      |    3-Response Authorization   |       |<-+
|      |<------------------------------------| Private Key |
|      |  access_token / refresh_token   |       |
|      |  token_type / expire_in      |       |
| Client  |                   +-------------+
|      |
|      |                   +-------------+
|      |    4-Request Resource      |       |
|      |-----------------------------------> |       |
|      | Authorization: bearer Access Token |       |--+
|      |                   | Resource  | | 5-Verify
|      |                   | Service   | | Token
|      |    6-Response Resource      |       |<-+
|      |<----------------------------------- | Public Key |
+-----------+                   +-------------+

通过上述的方式,我们可以很好地完成服务化后的用户认证。

用户权限

传统的单体应用的权限拦截,大家都喜欢shiro,而且用的颇为顺手。可是一旦拆分后,这权限开始分散在各个API了,shiro还好使吗?笔者在项目中,并没有用shiro。前后端分离后,交互都是token,后端的服务无状态化,前端按钮资源化,权限放哪儿管好使?

抽象与设计

在介绍灵活的核心设计前,先给大家普及一个入门的概念:RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。

RBAC其实是一种分析模型,主要分为:基本模型RBAC0(Core RBAC)、角色分层模型RBAC1(Hierarchal RBAC)、角色限制模型RBAC2(Constraint RBAC)和统一模型RBAC3(Combines RBAC)。

核心UML

这是笔者通过多种业务场景后抽象的RBAC关系图

类说明

Group

群或组,拥有一定数量权限的集合,亦可以是权限的载体。

子类:User(用户)、Role(角色)、Position(岗位)、Unit(部门),通过用户的特定构成,形成不同业务场景的群或组,而通过对群或组的父类授权,完成了用户的权限获取。

Permission

权限,拥有一定数量资源的集成,亦可以是资源的载体。

Resources

权限下有资源,资源的来源有:Menu(菜单)、Button(动作权限)、页面元素(按钮、tab等)、数据权限等

Program

程序,相关权限控制的呈现载体,可以在多个菜单中挂载。

常见web程序基本构成

模型与微服务的关系

如果把Spring Cloud服务化后的所有api接口都定义为上文的Resources,那么我们可以看到这么一个情况。

比如一个用户的增删改查,我们的页面会这么做

页面元素 资源编码 资源URI 资源请求方式
查询 user_btn_get /api/user/{id} GET
增加 user_btn_add /api/user POST
编辑 user_btn_edit /api/user/{id} PUT
删除 user_btn_del /api/user/{id} DELETE

在抽象成上述的映射关系后,我们的前后端的资源有了参照,我们对于用户组的权限授权就容易了。比如我授予一个用户增加、删除权限。在前端我们只需要检验该资源编码的有无就可以控制按钮的显示和隐藏,而在后端我们只需要统一拦截判断该用户是否具有URI和对应请求方式即可。

至于权限的统一拦截是放置在Zuul这个网关上,还是落在具体的后端服务的拦截器上(Filter、Inteceptor),都可以轻而易举地实现。不在局限于代码的侵入性。放置Zuul流程图如下:

要是权限的统一拦截放置在Zuul上,会有一个问题,那就是后端服务安不安全,服务只需要通过注册中心,即可对其他服务进行调用。这里就涉及到后面的第三个模块,服务之间的鉴权。

服务之间的鉴权

因为我们都知道服务之间开源通过注册中心寻到客户端后,直接远程过程调用的。对于生产上的各个服务,一个个敏感性的接口,我们更是需要加以保护。主题的流程如下图:

笔者的实现方式是基于Spring Cloud的FeignClient Inteceprot(自动申请服务token、传递当前上下文)和Mvc Inteceptor(服务token校验、更新当前上下文)来实现,从而对服务的安全性做进一步保护。

结合Spring Cloud的特性后,整体流程图如下:

优化点

虽然通过上述的用户合法性检验、用户权限拦截以及服务之间的鉴权,保证了Api接口的安全性,但是其间的Http访问频率是比较高的,请求数量上来的时候,的问题是就会特别明显。可以考虑一定的优化策略,比如用户权限缓存、服务授权信息的派发与混存、定时刷新服务鉴权Token等。

结语

上述是笔者在项目里的大体思路,有兴趣的朋友可以借鉴我的开源项目,欢迎star:
- gitchina:https://gitee.com/minull/ace-security(Jwt、用户权限)
- github:https://github.com/wxiaoqi/ace-security
- gitchina:http://git.oschina.net/geek_qi/ace-gate(服务鉴权)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • springcloud之自定义简易消费服务组件

    本次和大家分享的是怎么来消费服务,上篇文章讲了使用Feign来消费,本篇来使用rest+ribbon消费服务,并且通过轮询方式来自定义了个简易消费组件,本文分享的宗旨是:自定义消费服务的思路:思路如果有可取之处还请"赞"一下: Rest+Ribbon实现消费服务 Rest+轮询自定义简易消费组件 使用Scheduled刷新服务提供者信息 Rest+Ribbon实现消费服务 做为服务消费方准确的来说进行了两种主流程区分1)获取可以服务2)调用服务,那么又是如何获取服务的并且又是通过什么来

  • Spring Cloud 配置中心内容加密的配置方法

    从配置获取的配置默认是明文的,有些像数据源这样的配置需要加密的话,需要对配置中心进行加密处理. 下面使用对称性加密来加密配置,需要配置一个密钥,当然也可以使用RSA非对称性加密,但对称加密比较方便也够用了,这里就以对称加密来配置即可. 1.安装JCE JDK下的JCR默认是有长度限制的,需要替换没有长度限制的JCE版本. http://www.oracle.com/technet... 把下载包里面的两个jar文件复制替换到JAVA_HOME/jre/lib/security目录下. 2.添加加

  • Spring Cloud 请求重试机制核心代码分析

    场景 发布微服务的操作一般都是打完新代码的包,kill掉在跑的应用,替换新的包,启动. spring cloud 中使用eureka为注册中心,它是允许服务列表数据的延迟性的,就是说即使应用已经不在服务列表了,客户端在一段时间内依然会请求这个地址.那么就会出现请求正在发布的地址,而导致失败. 我们会优化服务列表的刷新时间,以提高服务列表信息的时效性.但是无论怎样,都无法避免有那么一段时间是数据不一致的. 所以我们想到一个办法就是重试机制,当a机子在重启时,同个集群的b是可以正常提供服务的,如果有

  • 详解使用Spring Cloud Consul实现服务的注册和发现

    首先安装consul环境,参照之前的文章:https://www.jb51.net/article/141789.htm 项目规划,2个服务端,1个客户端 首先来看服务端, 一:服务端1: 项目依赖 <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-clou

  • Spring Cloud 动态刷新配置信息教程详解

    有时候在配置中心有些参数是需要修改的,这时候如何不重启而达到实时生效的效果呢? 添加依赖 <dependencies> ... <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> ... </dependencies>

  • 详解SpringCloud Zuul过滤器返回值拦截

    Zuul作为网关服务,是其他各服务对外中转站,通过Zuul进行请求转发.这就涉及到部分数据是不能原封返回的,比如服务之间通信的凭证,用户的加密信息等等. 举个例子,用户服务提供一个登录接口,用户名密码正确后返回一个Token,此Token作为用户服务的通行证,那么用户登录成功后返回的Token就需要进行加密或者防止篡改处理.在到达用户服务其他接口前,就需要对Token进行校验,非法的Token就不需要转发到用户服务中了,直接在网关层返回信息即可. 要修改服务返回的信息,需要使用的是Zuul的过滤

  • SpringCloud客户端的负载均衡Ribbon的实现

    前言:微服务架构,不可避免的存在单个微服务有多个实例,那么客户端如何将请求分摊到多个微服务的实例上呢?这里我们就需要使用负载均衡了 一.Ribbon简介 Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP客户端的行为.为Ribbon配置服务提供者地址列表后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求.Ribbon默认为我们提供了很多的负载均衡算法,例如:轮询,随机等,也可自定义: Ribbon的GitHub: https://github.com/N

  • Spring Cloud Eureka服务治理的实现

    什么是Spring Cloud Eureka Spring Cloud Eureka 是 Spring Cloud 中的一个组件,它是基于 Netflix Eureka 做了二次封装,主要是负责完成微服务框架中服务治理的功能.Spring Cloud通过为 Eureka 增加了 Spring Boot 风格的自动化配置,我们只需要通过简单的引用依赖和注解就能让 Spring Boot 够将的微服务应用轻松的与 Eureka 服务治理体系进行整合. 服务治理 服务治理是微服务框架中最为核心和基础的

  • springcloud使用consul作为配置中心

    Spring Cloud 中文手册: https://springcloud.cc/spring-cloud-consul.html 也就是说在我们使用consul config时最好在consul 建立相应的目录结构 适用于某一个服务的目录结构以及适用于所有的服务的目录结构 本列consul web UI :springboot为我们提供了三种环境dev:默认开发环境  test:测试环境  prod:生产环境 PS: 1.每次当我们修改consul上面的配置信息的时候,会向我们的代码发送一个

  • 浅谈Spring Cloud下微服务权限方案

    背景 从传统的单体应用转型Spring Cloud的朋友都在问我,Spring Cloud下的微服务权限怎么管?怎么设计比较合理?从大层面讲叫服务权限,往小处拆分,分别为三块:用户认证.用户权限.服务校验. 用户认证 传统的单体应用可能习惯了session的存在,而到了Spring cloud的微服务化后,session虽然可以采取分布式会话来解决,但终究不是上上策.开始有人推行Spring Cloud Security结合很好的OAuth2,后面为了优化OAuth 2中Access Token

  • 详解spring cloud构建微服务架构的网关(API GateWay)

    前言 在我们前面的博客中讲到,当服务A需要调用服务B的时候,只需要从Eureka中获取B服务的注册实例,然后使用Feign来调用B的服务,使用Ribbon来实现负载均衡,但是,当我们同时向客户端暴漏多个服务的时候,客户端怎么调用我们暴漏的服务了,如果我们还想加入安全认证,权限控制,过滤器以及动态路由等特性了,那么就需要使用Zuul来实现API GateWay了,下面,我们先来看下Zuul怎么使用. 一.加入Zuul的依赖 <dependency> <groupId>org.spri

  • 浅谈Spring Cloud Netflix-Ribbon灰度方案之Zuul网关灰度

    Eureka默认集成了Ribbon,所以Ribbon的灰度实现原理就是借助服务注册到Eureka中的eureka.instance.metadata-map的内容来进行匹配的. Zuul网关的灰度实现也是借助了一个Ribbon的插件来实现,相对比较简单. 项目环境说明:有两个eureka的服务端(eureka-server),有两个相同的后端服务(service-sms),有一个网关服务(cloud-zuul). 1.网关的依赖: <?xml version="1.0" enco

  • Spring Cloud Alibaba微服务组件Sentinel实现熔断限流

    目录 Sentinel简介 Sentinel具有如下特性: 安装Sentinel控制台 创建sentinel-service模块 限流功能 创建RateLimitController类 根据URL限流 自定义限流处理逻辑 熔断功能 与Feign结合使用 使用Nacos存储规则 原理示意图 功能演示 Sentinel简介 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案,Sentinel 作为其核心组件之一,具有熔断与限流等一系列服务保护功能,本文将对其用法进行详细介

  • 浅谈Spring Cloud Ribbon的原理

    Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起.Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等.简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器.我们也很容易使用Ribbon实现自定义的负载均衡算法. 说起负载均衡一般都会想到服务端的负载均衡,常用产品包括LBS硬件或云服务.Nginx等,都是

  • 浅谈Spring Cloud中的API网关服务Zuul

    到目前为止,我们Spring Cloud中的内容已经介绍了很多了,Ribbon.Hystrix.Feign这些知识点大家都耳熟能详了,我们在前文也提到过微服务就是把一个大的项目拆分成很多小的独立模块,然后通过服务治理让这些独立的模块配合工作等.那么大家来想这样两个问题:1.如果我的微服务中有很多个独立服务都要对外提供服务,那么对于开发人员或者运维人员来说,他要如何去管理这些接口?特别是当项目非常大非常庞杂的情况下要如何管理?2.权限管理也是一个老生常谈的问题,在微服务中,一个独立的系统被拆分成很

  • spring cloud eureka微服务之间的调用详解

    微服务之间的调用如何实现 首先 你需要两个或以上的微服务模块 至于怎么创建可以参考我上一篇博客 spring cloud eureka注册中心 如果想在页面显示 那么需要先加上 compile 'org.springframework.boot:spring-boot-starter-thymeleaf' 这个thymeleaf依赖 springboot推荐使用thymeleaf模板 它的最大好处就是原型即是模板 后缀是html html文件 需要放在resources/templates文件夹

  • Spring Cloud Stream微服务消息框架原理及实例解析

    随着近些年微服务在国内的盛行,消息驱动被提到的越来越多.主要原因是系统被拆分成多个模块后,一个业务往往需要在多个服务间相互调用,不管是采用HTTP还是RPC都是同步的,不可避免快等慢的情况发生,系统性能上很容易遇到瓶颈.在这样的背景下,将业务中实时性要求不是特别高且非主干的部分放到消息队列中是很好的选择,达到了异步解耦的效果. 目前消息队列有很多优秀的中间件,目前使用较多的主要有 RabbitMQ,Kafka,RocketMQ 等,这些中间件各有优势,有的对 AMQP(应用层标准高级消息队列协议

  • spring cloud中微服务之间的调用以及eureka的自我保护机制详解

    上篇讲了spring cloud注册中心及客户端的注册,所以这篇主要讲一下服务和服务之间是怎样调用的 不会搭建的小伙伴请参考我上一篇博客:idea快速搭建spring cloud-注册中心与注册 基于上一篇的搭建我又自己搭建了一个客户端微服务: 所以现在有两个微服务,我们所实现的就是微服务1和微服务2之间的调用 注册中心就不用多说了,具体看一下两个微服务 application.yml配置也不用说了,不知道怎么配置的请参考我上篇博客 在project-solr中的constroller中: @R

  • 浅谈Spring Cloud Eureka 自我保护机制

    自我保护背景 首先对Eureka注册中心需要了解的是Eureka各个节点都是平等的,没有ZK中角色的概念, 即使N-1个节点挂掉也不会影响其他节点的正常运行. 默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例.但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制. 自我保护机制 官方对于自我保护机制的定义:

随机推荐