我在JWT上使用JHipster的网关,并且有一个微服务。
当其余调用从网关转发到微服务时,在微服务业务类中,我想获取经过身份验证的用户的用户ID。
这样做的原因是我想将它与实体一起保存在数据库中,以便一个用户的数据可以与另一个用户的数据完全分开(并且一个用户不能更新另一个用户的数据...等。)。 / p>
虽然我可以获取登录的用户名,但没有用户ID。
解决此问题的正确方法是什么?
(这对我来说没有太大意义,因为网关正在调用该服务,并且我想了解大多数服务的此信息)。
更新网关中的TokenProvider以包括用户ID? (不确定如何执行此操作)。这是正确的方法吗?
还有其他建议吗?
谢谢, Fergal。
注意:我看到其他类似的问题。这不是重复的问题。除非绝对确定,否则请勿将其标记为重复项。注意-我正在使用JWT
答案 0 :(得分:4)
为解决此问题,我在令牌中从网关向每个微服务添加了用户ID。
这是我在JHipster生成的代码中解决此问题的方法:
在网关中,将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)
请注意,我已将此添加到令牌提供者:
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;
});
}
最后,我现在可以从任何Business类调用此方法:
Optional<Long> userId = SecurityUtils.getUserId();
if (userId.isPresent()) {
log.info("User Id--->{}", userId.get());
} else {
log.info("No userId present.");
}
欢迎任何反馈。