I am using JHipster's Gateway with JWT and I have a microservice.
When the rest call is forwarded from the gateway to the microservice, in the microservice business class, I want to get the user id of the authenticated user.
The reason for this is I want to save it in the DB with the entity so that one user's data can be completely separate from other user's data (and a user cannot update another user's data...etc..).
While I can get the logged in user name, I don't have the user id.
What is the correct approach to resolving this issue:
(this doesn't make too much sense to me as the gateway is calling the service and I'll want to know this info for most services).
update the TokenProvider in the gateway to include a user Id ? (not certain how to do this). Is this the correct approach ?
any other suggestions ?
Thanks, Fergal.
Note: I see other similar questions. This is not a duplicate question. Do not mark this a duplicate unless absolutely certain. Note - I am using JWT
First, generate the entities in the microservice applications: this works as usual, and you can also use JHipster UML or JDL Studio to help you generate complex entities and relationships. As microservices don't have a front-end, no UI code will be generated. Then, on the gateway(s), run the entity sub-generator again.
A gateway is a JHipster-generated application (using application type microservice gateway when you generate it) that handles Web traffic, and serves an Angular/React application. There can be several different gateways, if you want to follow the Backends for Frontends pattern, but that's not mandatory.
JHipster UAA is a user accounting and authorizing service for securing JHipster microservices using the OAuth2 authorization protocol.
To solve this, I added the user id in the token from the gateway to each microservice.
Here is how I solved this in the JHipster generated code:
In Gateway, add UserService to UserJWTController, and get the user id, and use it when you are creating a token.
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);
...
add the claim to the token:
claim(USER_ID_KEY, userId)
note, I added this to Token Provider:
private static final String USER_ID_KEY = "userId";
and then in my microservice's app, I did this:
created a new class:
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;
}
}
and then I changed TokenProvider.getAuthentication to add the following lines:
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);
and then I added a new method to 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;
});
}
and finally, I can now call this method from any Business class:
Optional<Long> userId = SecurityUtils.getUserId();
if (userId.isPresent()) {
log.info("User Id--->{}", userId.get());
} else {
log.info("No userId present.");
}
Any feedback welcome.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With