【问题标题】:Jhipster Microservices - Correct way to get UserId in Microservices?Jhipster Microservices - 在微服务中获取 UserId 的正确方法?
【发布时间】:2018-10-31 10:28:12
【问题描述】:

我正在使用 JHipster 的网关和 JWT,并且我有一个微服务。

当rest调用从网关转发到微服务时,在微服务业务类中,我想获取认证用户的用户id。

这样做的原因是我想将它与实体一起保存在数据库中,以便一个用户的数据可以与其他用户的数据完全分开(并且一个用户不能更新另一个用户的数据......等等)。

虽然我可以获得登录用户名,但我没有用户 ID。

解决此问题的正确方法是什么:

  • 从微服务调用网关?

(这对我来说没有太大意义,因为网关正在调用服务,我想知道大多数服务的此信息)。

  • 更新网关中的 TokenProvider 以包含用户 ID ? (不确定如何执行此操作)。这是正确的方法吗?

  • 还有其他建议吗?

谢谢, 弗格尔。

注意:我看到其他类似的问题。这不是一个重复的问题。除非绝对确定,否则不要将其标记为重复。注意 - 我正在使用 JWT

【问题讨论】:

  • 我会通过替换主题或添加用户 ID 声明来更新 TokenProvider。
  • 谢谢@GaëlMarziou。我已经发布了我的代码,以便对其他人有所帮助。欢迎对我所采取的方法提供任何反馈。
  • 干得好。感谢您发布了您的代码。顺便说一下,您在 SamAuthenicationToken 的身份验证中忘记了一个“t”

标签: jhipster


【解决方案1】:

为了解决这个问题,我在每个微服务的网关令牌中添加了用户 ID。

这是我在 JHipster 生成的代码中解决这个问题的方法:

在Gateway中,将UserService添加到UserJWTController,并获取用户id,然后 在创建令牌时使用它。

public ResponseEntity<JWTToken> authorize(@Valid @RequestBody LoginVM loginVM) {
    ...
    ...
    Optional<User> user = userService.getUserWithAuthoritiesByLogin(loginVM.getUsername());
    Long userId = user.get().getId();
    String jwt = tokenProvider.createToken(authentication, rememberMe, userId);
    ...

将声明添加到令牌:

  claim(USER_ID_KEY, userId)

注意,我将此添加到 Token Provider:

  private static final String USER_ID_KEY = "userId";

然后在我的微服务应用中,我这样做了:

创建了一个新类:

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;

public class SamAuthenticationToken extends UsernamePasswordAuthenticationToken {

public Long getUserId() {
    return userId;
}

private final Long userId;

public SamAuthenticationToken(Object principal, Object credentials, Long userId) {
    super(principal, credentials);
    this.userId = userId;
}

public SamAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities, Long userId) {
    super(principal, credentials, authorities);
    this.userId = userId;
}
}

然后我更改了 TokenProvider.getAuthentication 以添加以下行:

    Long userId = null;
    Object userIdObj = claims.get(USER_ID_KEY);
    if (userIdObj != null) {
        String userIdStr = userIdObj.toString();
        userId = Long.parseLong(userIdStr);
        log.debug("Claim--> {}", userId);
    } else {
        log.debug("No user id in token");
    }

    User principal = new User(claims.getSubject(), "", authorities);
    return new SamAuthenticationToken(principal, token, authorities, userId);

然后我在 SecurityUtils 中添加了一个新方法

 public static Optional<Long> getUserId() {
    SecurityContext securityContext = SecurityContextHolder.getContext();
    return Optional.ofNullable(securityContext.getAuthentication())
        .map(authentication -> {
            if (authentication instanceof SamAuthenticationToken) {
                SamAuthenticationToken samAuthenticationToken = (SamAuthenticationToken) authentication;
                return samAuthenticationToken.getUserId();
            }
            return null;
        });
 }

最后,我现在可以从任何业务类调用此方法:

    Optional<Long> userId = SecurityUtils.getUserId();
    if (userId.isPresent()) {
        log.info("User Id--->{}", userId.get());
    } else {
        log.info("No userId present.");
    }

欢迎任何反馈。

【讨论】:

  • 您为什么要为此选择网关?
  • @ddsultan - 网关是最合适的地方,因为它是网关背后的许多服务所需要的。通过让网关来执行此操作,每个服务都不需要自己执行...如您所见,这是对网关的一个非常小的更改,但非常有用。我在一个项目中使用了 ISAM(IBM Security and Access Mgt),他们的反向代理正是这样做的。
  • @fergal_dd 非常感谢!你的实现对我帮助很大!!!
  • @RenanFranca - 很高兴听到这个消息......很高兴它帮助你继续前进。
猜你喜欢
  • 2019-11-03
  • 1970-01-01
  • 2021-08-26
  • 1970-01-01
  • 2017-07-12
  • 2018-01-02
  • 2016-11-22
  • 1970-01-01
  • 2018-03-29
相关资源
最近更新 更多