Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jhipster Microservices - Correct way to get UserId in Microservices?

Tags:

jhipster

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:

  • call the gateway from the microservice ?

(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

like image 825
fergal_dd Avatar asked Oct 31 '18 10:10

fergal_dd


People also ask

How do you use JHipster microservice?

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.

What is JHipster Gateway?

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.

What is JHipster UAA server?

JHipster UAA is a user accounting and authorizing service for securing JHipster microservices using the OAuth2 authorization protocol.


1 Answers

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.

like image 113
fergal_dd Avatar answered Nov 25 '22 22:11

fergal_dd