如何处理复合微服务请求中的验证?

8
考虑一个包含两个实体的应用程序:
  • User(包含基本用户数据,如姓名)
  • Passport(包含认证凭据,即密码)
再考虑两个内部微服务:
  • UserService(负责创建和管理用户及其基本数据)
  • AuthService(负责用户身份验证和密码处理)
User 实体属于 UserService,而 Passport 实体属于 AuthService。这两个服务之间必须分开,因为它们解决的任务非常不同:一个是处理“个人资料”(profile data),另一个是处理“身份验证”(authentication)。
此外,假设有一个注册表单,包括三个字段:
  • 电子邮件
  • 姓名
  • 密码
这个表单将触发 HTTP 请求发送到 GatewayService,后者会截取所有针对应用程序的请求并将其路由到内部微服务(或组成/聚合它们)。
现在,当网关服务接收到带有所有表单数据的请求时,需要执行以下操作:
  1. 调用 UserService 创建新用户(它将响应生成的 userId)。
  2. 调用 AuthService 为新创建的用户创建护照。它需要在第一步中收到的 userId 和原始请求中的 password 字段。
这看起来很简单,但是如果在第二步中无法使用 AuthService 呢?我们需要以某种方式分离这些请求!
经典方法是使用最终一致性,并通过异步调用创建 Passport 实体(我们可以将此请求放置在队列中并在单独的服务中处理它)。为此,我们将向 AuthService 发送异步请求,向其中传递 userIdpassword,而不是在第二步中执行操作,因此第一步将立即向客户端返回响应。
但是,如果 password 字段格式不正确(违反验证规则),该怎么办?验证逻辑仅存在于 AuthService 中,因此在进行调用之前无法确定密码是否正确。现在,请求正在异步处理,因此我们无法回到用户并告诉他更正密码。 那么,如何在面向微服务的应用程序中正确处理分布式组合请求的验证呢?
  1. 天真的解决方案是将验证逻辑移动到GatewayService本身,但这是一个可怕的想法,因为它会使其变得臃肿,并且会泄漏来自AuthService的业务逻辑。

  2. 另一个想法是提供一个额外的密码验证方法,并在步骤#1和#2之前调用它。看起来像是一种可行的解决方案,但它将强制我们在微服务中为每个业务方法拥有两个方法,一个用于前置验证,一个用于实际操作。此外,在验证和操作之间存在时间空间,因此当实际执行操作时,早期的正确值可能变为不正确。

  3. 我们可以将表单分成两个部分,以避免复合请求,并在询问个人数据并为用户创建帐户后要求他输入密码。然而,这可能会导致安全问题,例如用户帐户可能会被其他人截取,其他人可能会猜测下一个userId。我们可以使用一些额外的安全令牌,但这将向服务引入奇怪的功能,并使整个设置更加复杂。

    此外,这种方法看起来像是试图逃避问题,你不能总是避免复合请求。

  4. 我们可以使用完整的分布式事务,例如2PC,但这将使系统显着复杂,并且在首次使用MSA时会减弱其使用。

  5. 最后一个想法是将这两个服务合并在一起,但在微服务架构中这样做没有任何意义。

3个回答

1

这是我的想法

1. 用户服务 - 应负责

创建用户,包括用户名、密码(哈希)、电子邮件和任何其他配置文件数据

根据验证规则验证输入数据

使用密码验证用户

优点

进一步添加配置文件数据很容易

在单个请求中查找和验证用户

与用户有关的登录只需在一个地方进行

2. 身份验证服务 只需要根据通过用户服务的成功用户验证生成令牌

这些令牌应用于生态系统中所有其他服务的进一步处理,并确保适当的授权

优点

将来需要用户身份验证和授权的服务的进一步添加可以独立工作,并且仅需要安全令牌。

基于先前令牌生成令牌可以很容易,用户不需要每次令牌即将过期时输入用户名和密码。


0
关于第5点,我真的没有看到你在这里合并成一个服务(第5点),一种“用户管理服务”,它可以同时处理这两个任务,会违反原则。即使可以争论一个微服务应该执行一个任务并且做得很好,但是在我看来,这两个任务是密切相关的。
另一个选择是将UserService作为AuthService的同步客户端(负载平衡、断路器等,以确保一个实例的可用性),这基本上与在“正常”代码中注入密码验证的依赖项相同。
如果这是一个全新的项目,并且你不必坚持使用这两个服务,通常情况下,我会选择更简单的第一次实现,并抵制优化的冲动,因为这些倾向于过早地出现,或者是对原则/教条的不必要承诺。你自己也意识到了你可能引入的复杂性(2PC),再加上你有你的需求(“所以我们不能回到用户那里告诉他纠正密码”)。

0

我同意第五点。由于访问UserService将始终涉及AuthService,因此这两个服务将具有许多依赖关系,并且它们可能访问相关数据。 如果您将它们分开,则可能需要分开它们的共享逻辑,例如生成护照。它可以在一个服务中,该服务具有接收来自AuthService(在验证凭据后)或来自UserService(在注册后)的userID的操作。

此外,处理缺少AuthService将引发其他情况的问题,例如如果用户已经注册但无法登录,您如何处理?..如果您正在显示错误消息,为什么不在注册时就显示呢?..这只是一个关于您的要求的更多思考的问题。

干杯


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接