Jhipster微服务-在微服务中获取UserId的正确方法?

fer*_*_dd 4 jhipster

我正在将JHipster的Gateway与JWT一起使用,并且具有微服务。

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

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

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

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

  • 从微服务调用网关?

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

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

  • 还有其他建议吗?

谢谢,费尔加尔

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

fer*_*_dd 5

为了解决这个问题,我在令牌中从网关向每个微服务添加了用户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);
    ...
Run Code Online (Sandbox Code Playgroud)

将声明添加到令牌中:

  claim(USER_ID_KEY, userId)
Run Code Online (Sandbox Code Playgroud)

注意,我将此添加到令牌提供者:

  private static final String USER_ID_KEY = "userId";
Run Code Online (Sandbox Code Playgroud)

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

创建了一个新类:

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;
}
}
Run Code Online (Sandbox Code Playgroud)

然后我更改了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);
Run Code Online (Sandbox Code Playgroud)

然后我向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;
        });
 }
Run Code Online (Sandbox Code Playgroud)

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

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

欢迎任何反馈。