【问题标题】:Data validation across different microservices跨不同微服务的数据验证
【发布时间】:2019-02-17 07:27:21
【问题描述】:

我已经阅读了很多关于它的主题,但仍然没有找到更好的方法。

我有一个User。一个User 可能有多个Posts。用户和帖子是不同的微服务。我正在使用 Spring Boot。

当前端调用我的Posts 微服务向/posts/user/1 发送POST 请求时,我需要检查给定的userId (1) 是否存在于我的Users 数据库中。如果否,则抛出异常,告诉前端用户不存在。如果是,则将给定的请求正文插入为Post

问题是:我应该如何在我的后端检查这些信息?我们不想让前端承担这个责任,因为 javascript 是客户端,恶意用户可以绕过这个检查。

选项:

  • 微服务之间的 REST 通信。 (发微服务调用用户微服务询问给定的id是否在他身边)
  • 授予 Posts 微服务访问用户微服务数据库的权限

我知道他们之间的通信会产生耦合,但我不确定授予 Posts 访问用户数据库是否是最佳选择。

欢迎提出任何建议。

【问题讨论】:

  • 数据至关重要,必须加以保护。因此,在我看来,拥有位于后端顶部的服务(在您的情况下为数据库)并通过使用适当的身份验证和访问控制公开公共端点是很好的

标签: java rest spring-boot architecture microservices


【解决方案1】:

对于这个非常特殊的用例,如果您有一个安全层,您可以(应该)使用用户访问令牌,以确保为正确的用户处理该请求,这可以通过验证令牌和依赖于如果用户拥有他存在的令牌这一事实。 (因为它与用户是否存在无关)

对于除此之外的任何逻辑,假设您要检查他是否被允许发布或其他此类限制,需要调用用户服务。

谈到授予对数据库的访问权限,这将违反微服务的一项基本准则。这样做会在您和用户之间形成紧密的耦合。在这种情况下可以调用用户服务,它可以决定如何处理这个请求。 用户服务本身应提供通过缓存或其他机制在 SLA 内回答您的查询的方法。

您可以探索的另一件事是BFF(前端的后端) 你说得对,你不应该将后端服务暴露给前端或在那里添加任何逻辑,但通常前端页面可能不愿意接受同一页面上的内容是通过 n 个不同的后端服务来回答的,并且可能有一些逻辑来拼接这样的查询这就是你可以使用 BFF 的地方。 后端服务器(在我的例子中是节点),它需要前端对给定页面进行一次调用(或更少调用),同时将后端服务隐藏在其中。

【讨论】:

    【解决方案2】:

    你是对的,你必须在后端进行验证,因为我想它是一个 REST 服务,并且请求不仅可以从 UI 发送。

    假设你有一个服务实现:

    @Service
    class UsersServiceImpl implements UsersService {
    
      private final Users users;
    
      public UsersServiceImpl(Users users) {
        this.users = users;
      }
    
      @Override
      public void addPost(long userId, Post post) {
        User user = users.get(userId);
        if (user == null) {
          throw new UserNonExistent(userId);
        }
        user.addPost(post);
      }
    }
    

    其中Users 是代表用户数据库的接口,UserNonExistentRuntimeException。然后在您的控制器中,您可以执行以下操作:

    @RestController
    class UsersController {
    
      private final UsersService usersService;
    
      public UsersController(UsersService usersService) {
        this.usersService = usersService;
      }
    
      @PostMapping("/posts/user/{userId}")
      public void addPostToUser(@PathVariable String userId, @RequestBody Post post) {
        usersService.addPost(userId, post);
      }
    
      @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "User does not exist")
      @ExceptionHandler({UsersService.UserNonExistent.class})
      public void handleUserNonExistentException() {
        // Nothing to do
      }
    }
    

    如果提供的用户 ID 无效,handleUserNonExistentException() 方法将被调用并返回一个BAD REQUEST HTTP 状态码。

    【讨论】:

    • 这个答案假设服务器是一个整体,而 OP 明确表示问题是关于微服务的。
    【解决方案3】:

    您可以选择通过RESTful 方法在PostUser 微服务之间进行进程间通信。

    如果您只想检查资源的存在并且不希望任何主体响应,那么您应该使用HEAD http 方法。因此,您在 User 微服务上托管的 API 端点看起来像 -

    HEAD  user/{userId}
    

    Post微服务调用这个API。

    如果用户存在则返回 200 / OK

    如果用户不存在则返回 404 / Not Found

    Click herehere 以获取有关 HEAD 方法用法和用例的更多详细信息。

    【讨论】:

      猜你喜欢
      • 2019-03-21
      • 2019-05-24
      • 2017-10-19
      • 2021-02-07
      • 2018-07-28
      • 2021-12-10
      • 2018-05-12
      • 2017-08-19
      • 1970-01-01
      相关资源
      最近更新 更多