OAuth2在微服务架构中的典型场景

引言

面对现如今多形态的基于HTTP RESTful风格的应用架构体系(传统WEB、微服务、SPA、桌面端、移动端、IOT等),OAuth2.0 & OIDC 1.0提供了一套通用的用户认证与授权的最佳实践,而JWT(Json Web Token)作为OAuth2中的Token的实际载体因其安全性、无状态等特性也得到了广泛使用。现如今市面上越来越多的提供OAuth2.0 & OIDC1.0(OpenID Connect)接入的IDaaS(ID as a service)身份服务商(如Auth0、Authing、Azure ADFS等)的涌现,也说明了OAuth2.0 & OIDC 1.0的体系的逐步完善与流行。OAuth2.0引入了授权服务器Authorization Server、客户端Client、资源服务器Resource Server等概念,解耦并明确划分了各角色的职责,而这些角色也可以对应到微服务架构中。

关于OAuth2.0 & OIDC1.0授权模式的选择可参见下图:
在这里插入图片描述

传统Web应用(前后端不分离)

早期的Web应用采用前后端不分离的架构,即后端采用模板引擎(JSP、Thymeleaf等)的方式进行前端页面的开发,
此时的统一用户认证中心即对应OAuth2中的授权服务器Web应用即可作为OAuth2中的客户端,且Web应用采用授权码模式接入OAuth2。
Web应用的职责包括:

  • 拦截未认证的HTML页面请求并302重定向到统一认证中心(即对应OAuth2的授权服务器)的授权端点
  • 拦截未认证的JS、图片等资源请求并返回401
  • 拦截未认证的Ajax请求并返回401及对应的授权端点URL(由前端页面JS自行跳转)
  • 暴露OAuth2授权回调端点,由统一认证中心携带授权码回调此端点,然后由Web应用换取access_token及用户信息,并写入Web应用的当前Session中

或者更简单的处理方式:

  • 不对HTML页面、JS、图片等资源请求进行认证拦截
  • 仅拦截未认证的Ajax请求并返回401及对应的授权端点URL(由前端页面JS自行跳转)
  • 暴露OAuth2授权回调端点,由统一认证中心携带授权码回调此端点,然后由Web应用换取access_token及用户信息,并写入Web应用的当前Session中

之后Web应用的前端页面和后端通过Session(Cookie)保持会话及登录态(用户信息),至此以完成OAuth2授权流程,而后的登录状态可由当前Web应用自行维护,
如此也即类似早期传统Web应用接入如微信等第三方登录的方式,
同时由于Web应用采用了Session机制,所以在Web应用支持分布式部署的场景下,即需要支持脱离Web容器(如Tomcat)的集群Session存储,例如使用Spring Session Redis跨服务间管理Session。
在这里插入图片描述

前后端分离

随着前后端开发的分离,前端已被作为独立的工程进行管理,当前前端采用较流行的SPA开发模式(VUE、React等)且独立部署,而后端服务仅提供API服务,
此时依旧保留统一用户认证中心即对应OAuth2中的授权服务器
前端应用作为OAuth2中的客户端,以授权码+PKCE模式、刷新令牌模式接入OAuth2,
前端应用对后端API服务发起请求,后端服务需对前端页面发起的请求进行认证与鉴权,如此后端服务即作为OAuth2中的资源服务器
前端应用作为OAuth2客户端,其主要职责包括:

  • 引导用户跳转(附加PKCE挑战码coder_challenge)到统一用户认证授权页面(即对应OAuth2.0授权端点Authorization Endpoint)。
  • 处理授权码Authroization Code回调请求,携带授权码(附加PKCE验证码coder_verifier)调用统一用户认证服务(即对应OAuth2.0的令牌端点Token Endpoint)换取访问令牌Access Token、身份令牌ID Token和刷新令牌Refresh Token。
  • 验证身份令牌ID Token(签名验证、属性验证aud、azp、nonce等)
  • 安全地存储令牌(加密存储 或session存储)。
  • 携带访问令牌Access Token获取并存储用户详细信息(即对应OIDC1.0 UserInfo Endpoint)
  • 携带访问令牌Access Token(Bearer Token)访问后端API服务
  • 待访问令牌即将过期时自动刷新令牌

可以发现,客户端的工作内容还是比较多的,但是借助相关的OIDC开发框架(如SPA端的openid-connect,Java端的spring-boot-starter-oauth2-client),集成还是很方便的。

后端API服务作为OAuth2的资源服务器,其主要职责包括:

  • 对请求中的Bearer access_token进行认证及鉴权

参考Spring Security OAuth2 Resource Server框架实现,后端API服务可以采用如下两种方式对access_token进行认证:

  • JWT:Resource Server端通过public JWK(JWT签名公钥或其发现端点)对令牌中的签名进行验证
  • Opaque Token:Resource Server端调用授权服务器(即之前的用户认证中心)端的令牌验证端点(introspection-uri)对令牌进行验证

此架构明确划分了前后端在OAuth2中的角色与职责,且前后端无需维持Session,

但问题是每当后端新增加服务时,新增加的后端服务都需要接入同样OAuth2资源服务器配置,假如认证方式有调整会牵涉到所有后端接入服务。
在这里插入图片描述

前后端分离 +应用网关

在前一章前后端分离架构的基础之上,引入了应用网关的角色,如采用Spring Cloud Gateway实现,
将用户鉴权的操作前置到网关层,即由应用网关作为OAuth2的资源服务器

  • 应用网关仅对access_token进行认证,认证通过才会转发请求到后端服务
  • 应用网关无状态(无需session维护用户登录态、用户信息等)
  • 后端服务无需关心OAuth2,后端的服务实现仅需关注核心业务逻辑即可

此种方式也即是OAuth2在微服务架构中的典型应用场景

如果后端API服务有获取用户身份的需要(例如需根据用户身份查询数据、确定操作人等),可参见如下几种实现方式:

  • 应用网关将客户端请求中携带的请求头Authorization: Bearer AccessToken透传到后端服务,后端服务通过解析此Access Token(无需JWT签名公钥)中的相关属性便可获取对应的用户信息(如JWT sub)。
  • 可在应用网关处对AccessToken属性(如JWT sub)进行解析,生成用户信息后再通过指定请求头透传到后端服务,后端服务可直接通过该请求头获取用户信息。
  • 由客户端提供用户信息(解析ID Token或者UserInfo)作为参数或者请求头,然后由网关透传到后端服务,后端服务可直接解析对应的用户信息。

在这里插入图片描述

应用网关作为OAuth2客户端

将应用网关作为OAuth2中的资源服务器是比较理想的状态(职责划分清晰、网关无状态),但需要前端SPA客户端承担一定接入OAuth2的工作量。
如果接入OAuth2协议的Client端,如SPA(浏览器端)、Native App(移动app、桌面应用)具有独立完成OAuth2认证接入(如授权码模式)的能力(语言框架支持、开发人员可以配合修改代码),还是首选应用网关仅作为资源服务器。
但是针对浏览器端应用(支持Cookie Storage、支持302重定向),如果Client端不具备接入OAuth2认证的能力,又或者为了减轻Client端的接入复杂程度,也可由应用网关承担OAuth2客户端的接入工作,
应用网关作为OAuth2的Client端,以授权码模式、刷新令牌模式(可选) 接入OAuth2。
此架构下应用网关作为OAuth2客户端与浏览器端SPA应用通过Session Cookie保存用户会话及登录态,所以为了保证应用网关支持水平扩展,所以应用网关亦需要支持集群Session存储,例如使用Spring Session Redis跨服务间管理Session。
在这里插入图片描述

以Spring Cloud Gateway(以下简称SCG)作为网关实现为例,在上述架构中,可以将应用分为3类:

  • 第1类:前端应用 - 运行在浏览器端,向SCG发送请求

    • SPA - 独立运行的SPA应用(如Vue),可与SCG部署在不同域名下
      • 通过Ajax请求SCG后端服务
      • 与SCG可能存在跨域
    • Web Template/Ajax - 通过请求后端Web应用渲染Template页面(如Thymeleaf、JSP等)
      • 请求html页面
      • html页面中亦存在Ajax请求,即Ajax请求SCG后端服务
      • html页面和页面中的Ajax请求可隶属于同一Web应用,亦可跨Web应用
      • 通过SCG请求,即与SCG同域名
  • 第2类:后端应用 - 由SCG代理的后端应用

    • Resource Server - 后端API服务,不包含页面
      • 可接入OAuth2 Resource Server,对请求中的bearer access_token(由SCG透传到后端服务)进行认证
    • Web Template/Ajax - 传统web应用,同时提供html页面(如Thymeleaf、JSP等)和Api服务(支持Ajax调用)
  • 第3类:应用网关SCG Client - 负责接入OAuth2授权、维护用户Session及Cookie、透传access_token到后端服务

    • 若浏览器向SCG发起未认证的请求
      • html页面请求(text/html) - 302重定向到SCG Client授权端点
      • Ajax请求(xhr - application/json) - 返回Http 401 Unauthorized
    • 代理OAuth2授权 - /oauth2/authorization/{clientRegId} - 触发SCG Client的OAuth2登录流程
    • 处理OAuth2授权回调 - /login/oauth2/code/{clientRegId}?code=…state=…
    • 获取token、刷新token、透传token到后端服务
    • 维护用户Web Session

前端应用SCG Client间通过Session Cookie来保持用户状态,即由SCG Client完成OAuth2授权流程后,首先将授权信息(access_token、refresh_token、id_token、userInfo)写入到SCG端Session存储,然后再向浏览器端写Session Cookie,之后前端应用(同域、跨域)向SCG发送请求时,会携带SCG域名下的Session Cookie,SCG对Session Cookie认证通过后,可以将access_token透传到后端应用

SPA作为前端应用接入SCG Client的完整认证过程参见如下顺序图:
在这里插入图片描述

如上图,SPA接入SCG Client,仅需统一处理Ajax调用返回的Http status 401 Unauthorized,
在收到401后,可统一重定向到SCG Client的自身的OAuth2 Authorization Endpoint:
https://scg-client/oauth2/authorization/{clientRegId}?redirect_uri=https://spa
同时可附加redirect_uri参数,此参数用于设置SPA自身的地址,
SCG Client会在完成OAuth2授权流程后再重定向回此参数指定的uri地址,即重定向回SPA,
此redirect_uri为扩展参数,后文有讲解,并非Spring Security OAuth2 Client原生支持的。

如果后端Api服务不想被任意访问,则SCG可为后端route配置TokenRelay过滤器,即将bearer access_token透传到后端的API服务,
而后端Api服务可以接入Spring Security OAuth2 Resource Server模块来完成对access_token的校验。
如果后端Api服务在部署在内网,不可被公开访问,亦可不开启TokenRelay过滤器,因为SCG Client已经完成过OAuth2登录,即已经认证过用户,所以后端Api服务可无需再对用户进行认证,若有获取用户信息的需要,可参见下面讲解中提到的自定义UserInfoRelay过滤器,将SCG Web Session的用户信息透传到后端Api服务即可。

SCG Client代理Web Template/Ajax服务的完整认证过程参见如下顺序图:
在这里插入图片描述
如上图,Web Template/Ajax接入SCG Client,
对于Html页面请求,SCG Client通过SaveRequest、302重定向机制自动完成OAuth2授权流程,
而对于Html页面中的发送后端服务的Ajax请求,仅需统一处理Ajax调用返回的Http status 401 Unauthorized,
在收到401后,可统一重定向到任一Html页面请求(如Homepage),请求Html页面即可由SCG Client自动完成OAuth2授权流程,

若后端服务有获取用户信息的需求,可自定义UserInfoRelay过滤器(实现逻辑参考TokenReplay),
SCG仅需将Web Session中的SPRING_SECURITY_CONTEXT用户信息透传到到后端服务,
而后端服务可根据需要读取x-user-info请求头获取用户信息(无需接入OAuth2 ResourceServer)。

猜你喜欢

转载自blog.csdn.net/luo15242208310/article/details/126179619
今日推荐