如何将用户角色从授权服务器复制到下游微服务?

Posted

技术标签:

【中文标题】如何将用户角色从授权服务器复制到下游微服务?【英文标题】:How can I replicate user roles from an Authorization Server to downstream microservices? 【发布时间】:2017-11-22 22:04:27 【问题描述】:

我需要实现一个应用程序,我将在其中使用生成 JWT 令牌的授权服务器。这些令牌将包括用户被授予的角色,然后授权用户访问不同的资源。还将有一个添加此安全性的网关。

我的问题是关于用户角色和内部微服务之间的安全性。

当用户被创建时,他应该被授予一组角色,并且他可能会在稍后被授予不同的角色,或者稍后可能会添加新的角色。所有这些信息都应该存储在授权服务器中。但是这些信息是如何复制到其他微服务的呢?如果我使用 Spring Security 之类的框架来保护我的端点,在其中添加不同 URL 所需的角色,我是否需要将用户角色硬编码到下游微服务中的安全配置中,或者是否有任何其他方法可以从中找到它们授权服务器?

该架构将在公共网络中使用 API 网关,然后与内部网络中的服务发现进行通信以查找不同的微服务。这些也通过服务发现找到彼此。我使用 Zuul 进行路由。在这种情况下,我是否还需要保护内部网络内的通信?我知道要使用 Spring Security 进行授权,无论如何我都需要传递 JWT 令牌来获取用户角色。但否则有必要吗?从客户端到网关使用 HTTPS 并在专用网络中使用不安全的 HTTP 就足够了吗?

【问题讨论】:

【参考方案1】:

这里有很多选择。

其中之一是您可以将spring-security-oauth2 与弹簧安全性结合使用。在此设置中,您将区分两种应用程序:

授权服务 (AS) - 此服务发布并验证访问令牌以验证客户端(例如使用密码授予或授权代码); 资源服务 (RS) - 例如,它为资源上的 CRUD 操作公开了一个 REST API。端点受到保护。 RS 与 AS 通信以授予访问权限;

在资源服务器中,您将像在独立应用程序中一样使用和配置 Spring Security。下面是一个非常简单的例子。

这是带有受保护端点的 REST 控制器中的代码:

@PreAuthorize("hasRole('READ_BOOK')")
@GetMapping(value = "/books/id")
public ResponseEntity<Book> getBook(@PathVariable("id") String id) 
    ...
    //retrieves book details if you have role READ_BOOK


@PreAuthorize("hasRole('WRITE_BOOK')")
@PostMapping(value = "/books")
public Book createBook(@RequestParam("title") String title) 
    ...
    //creates a book if you have role WRITE_BOOK

安全配置看起来就像您正在编写一个单体应用程序,但以下情况除外:

您将在配置中添加@EnableResourceServer 注释; 您将配置一个RemoteTokenServices 的实例 - 此服务的任务是根据授权服务器验证提供的令牌并获取用户角色;

AS 将根据一些OAuth2 工作流程颁发访问令牌。客户端将使用这些令牌来访问受保护的端点。

我制作了一个小型 PoC(概念验证)设置,在其中我创建了两个简单的应用程序来展示整个操作。请找到它here 并随时提交问题、建议和 PR。包含完整的源代码,并附有更多解释。

请注意,在某些情况下,此设置可能会导致过多的服务间通信。我见过一个更复杂的设置,其中 API 网关充当资源服务器,如果用户有足够的凭据,它会用必要的细节丰富请求,并将请求传递给基本上信任网关的下游服务。

【讨论】:

但在这种情况下,我的第一个问题仍然存在。然后我需要对每个控制器允许的用户角色进行硬编码吗?使用 @PreAuthorize 注释需要我预先知道角色。它们的任何更改都会迫使我同时更改 AS 和控制器。可能就是这样,我在问以防我遗漏了什么。 另一个问题是我提到我正在使用 Zuul。现在,我的 RS 是一个反向代理,包括带有 Angular 的前端。它使用 HTTP 调用由 Zuul 转换为 URL 的名称,因此没有任何我可以注释的手工控制器。那么在这种情况下,有什么开箱即用的东西可以用来为使用 Zuul 配置的 URL 添加授权吗? 对于第一个问题 - 是的 - 角色应该预先知道,这是 IMO 的正常情况。我无法回答 Zuul 的问题 - 一个非常基本的设置(我谈到过)将如下所示:获取令牌:前端 -> Zuul -> AS。访问资源:前端 -> Zuul -> RS AS。我无法详细说明 Zuul 直接与 AS 通信的设置。 感谢您的帮助。我从阅读有关该主题的内容中了解到,您可以选择往返于 AS 以验证每个请求的令牌,或者当令牌类似于 JWT 编码和签名时让 RS 验证签名哈希算法。然后,还可以选择混合两者,其中客户端仍然只存储访问令牌,然后有一个反向代理来验证它,并创建一个 JWT 令牌,其中包含来自客户端的发送到 RS 的声明。在这种方法中,它将是:FE -> Zuul AS --> RS with token.

以上是关于如何将用户角色从授权服务器复制到下游微服务?的主要内容,如果未能解决你的问题,请参考以下文章

授权服务如何在基于角色的微服务架构中实现所有权检查

如何在微服务架构中进行身份验证和授权

微服务和用户之间的授权

微服务的用户认证与授权杂谈

在微服务之间传递用户身份和授权

在微服务架构中组织授权的最佳实践?