12 | 架构案例:基于OAuth 2.0/JWT的微服务参考架构

12 | 架构案例:基于OAuth 2.0/JWT的微服务参考架构

架构图
12 | 架构案例:基于OAuth 2.0/JWT的微服务参考架构_第1张图片

  1. 令牌的校验和转换,将前端传递过来的 OAuth 2.0 访问令牌,通过调用 IDP 进行校验,并转换为包含用户和权限信息的 JWT 令牌,再将 JWT 令牌向后台微服务传递。
  2. 权限校验,网关的路由表可以和 OAuth 2.0 的 Scope 进行关联。这样,网关根据请求令牌中的权限范围 Scope,就可以判断请求是否具有调用后台服务的权限。

IDP 服务:IDP 是 Identity Provider 的简称,主要负责 OAuth 2.0 授权协议处理,OAuth 2.0 和 JWT 令牌颁发和管理,以及用户认证等功能。IDP 使用后台的 Login-Service 进行用户认证。
BFF 层:主要实现对后台领域服务的聚合(Aggregation,有点类似数据库的 Join)功能,同时为不同的前端体验(PC/Mobile/ 开放平台等)提供更友好的 API 和数据格式。
领域服务层:领域服务层在整个微服务架构的底层。这些服务包含业务逻辑,通常有自己独立的数据库存储,还可以根据需要调用外部的服务。

场景 1:第一方 Web 应用 + 资源拥有者凭据模式

12 | 架构案例:基于OAuth 2.0/JWT的微服务参考架构_第2张图片

  1. 用户通过浏览器访问 ACME 公司的电商网站,点击登录链接。
  2. Web 应用返回登录界面(这个登录页可以是网站自己定制开发)。
  3. 用户输入用户名、密码进行认证。
  4. Web 应用将用户名、密码,通过网关转发到 IDP 的令牌获取端点(POST /oauth2/token,grant_type=password)。
  5. IDP 通过 Login Service 对用户进行认证。
  6. IDP 认证通过,返回有效访问令牌(根据需要也可以返回刷新令牌)。
  7. Web 应用接收到访问令牌,创建用户 Session,并将 OAuth 2.0 令牌保存其中,然后返回登录成功到用户端。
  8. 用户浏览器中记录 Session Cookie,登录成功。

认证授权之后的服务调用流程
12 | 架构案例:基于OAuth 2.0/JWT的微服务参考架构_第3张图片

  1. 用户登录后,在网站上点击查看自己的购物历史记录。
  2. Web 应用通过网关调用后台 API(查询用户的购物历史记录),请求 HTTP header 中带上 OAuth 2.0 令牌(来自用户 Session)。
  3. 网关截取 OAuth 2.0 令牌,去 IDP 进行校验。
  4. IDP 校验令牌通过,再通过令牌查询用户和 Scope 信息,构建 JWT 令牌,返回。
  5. 网关获得 JWT 令牌,校验 Scope 是否有权限调用 API,如果有就转发到后台 API 进行调用。
  6. 后台 BFF(或者领域服务)通过传递过来的 JWT 获取用户信息,根据用户 ID 查询购物历史记录,返回。
  7. Web 应用获得用户的购物历史数据,可以根据需要缓存在 Session 中,再返回用户端。
  8. 购物历史数据返回到用户浏览器端。

场景 2:第一方移动应用 + 授权码许可模式

12 | 架构案例:基于OAuth 2.0/JWT的微服务参考架构_第4张图片

  1. 用户访问电商 App,点击登录。
  2. App 生成 PKCE 相关的 code verifier + challenge。
  3. App 以内嵌方式启动手机浏览器,访问 IDP 的统一认证页 (GET /authorize),请求带上 PKCE 的 code challenge 相关参数。
  4. IDP 返回统一认证页。
  5. 用户认证和授权。
  6. IDP 通过 Login Service 对用户进行认证。
  7. IDP 返回授权码到 App 浏览器。
  8. App 截取浏览器带回的授权码,将授权码 +PKCE code verifer,通过网关转发到 IDP 的令牌获取端点(POST /oauth2/token, grant_type=authorization-code)。
  9. IDP 校验 PKCE 和授权码,校验通过则返回有效访问令牌。
  10. App 获取令牌,本地存储,登录成功。

场景 3:第三方 Web 应用 + 授权码模式

12 | 架构案例:基于OAuth 2.0/JWT的微服务参考架构_第5张图片

  1. 用户访问这个第三方 Web 应用,点击登录链接。
  2. Web 应用后台向 ACME 公司的 IDP 服务发送申请授权码请求(GET /authorize)。
  3. 用户被重定向到 ACME 公司的 IDP 统一登录页面。
  4. 用户进行认证和授权。
  5. IDP 通过 Login Service 对用户进行认证。
  6. 认证和授权通过,IDP 返回授权码。
  7. Web 应用获得授权码,再向 IDP 服务的令牌获取端点发起请求(POST /oauth2/token, grant_type=authorization-code)。
  8. IDP 校验授权码,校验通过则返回有效 OAuth 2.0 令牌(根据需要也可以返回刷新令牌)。
  9. Web 应用创建用户 Session,将 OAuth 2.0 令牌保存在 Session 中,然后返回登录成功到用户端。
  10. 用户浏览器中记录 Session Cookie,登录成功。

额外说几点
第一点是,IDP 的 API 要支持从 OAuth 2.0 访问令牌到 JWT 令牌的互转。今天我们提到的集成架构采用 OAuth 2.0 访问令牌 + JWT 令牌的混合模式,中间需要实现 OAuth 2.0 访问令牌到 JWT 令牌的互转。这个互转 API 并非 OAuth 2.0 的标准,有些 IDP 产品(比方 Spring Security OAuth)可能并不支持,因此需要用户定制扩展。
第二点是**,关于单页 SPA 应用场景**。关于单页 SPA 应用场景,简单做法是采用隐式许可,但是这个模式是 OAuth 2.0 中比较不安全的,
第三点是,关于 SSO 单点登录场景。为了简化描述,上面的流程没有考虑 SSO 单点登录场景。如果要支持 Web SSO,那么各种应用场景都必须通过浏览器 +IDP 登录页集中登录,并且 IDP 要支持 Session,用于维护登录态。如果 IDP 以集群方式部署的话,还要考虑粘性 Sticky Session 或者集中式 Session。
第四点是关于 IDP 和网关的部署方式。前面的几张架构图中,IDP 虽然躲在网关后面,但实际上 IDP 可以直接通过 Nginx 对外暴露,不经过网关。或者,IDP 的登录授权页面,可以通过 Nginx 直接暴露,API 接口则走网关。
第五点是关于刷新令牌。为了简化描述,上面的流程没有详细说明刷新令牌的集成方式。企业根据场景需要,可以启用刷新令牌,来延长用户的登录时间,具体的集成方式需要考虑安全性的需求。
第六点是关于 Web Session。为了简化描述,在上面的流程中,Web 应用登录成功后假设启用 Web Session,也就是服务器端 Session。在实际场景中,Web Session 并非唯一选择,也可以采用简单的客户端 Session 方式,也称无状态 Session,也就是在客户端浏览器 Cookie 中保存 OAuth 2.0 访问令牌。

全程使用oauth2令牌,那么网关之后的每个微服务都需要自己根据令牌token去idp或者redis或者mysql中去查询用户信息,如果全程使用jwt令牌,主要是还是由于jwt自包含用户信息,存在暴露用户信息的安全风险。(如果jwt中只存在用户名,不存在其他相关信息也可以考虑全程使用jwt令牌)

原文

你可能感兴趣的:(OAuth,2.0,微服务,架构,java)