Jhipster microservices - правильный способ получить userid в микросервисах?

Я использую шлюз JHipster с JWT, и у меня есть микросервис.

Когда остальной вызов перенаправляется со шлюза на микросервис в бизнес-классе микросервиса, я хочу получить идентификатор пользователя, прошедшего проверку подлинности.

Причина этого в том, что я хочу сохранить его в базе данных вместе с объектом, чтобы данные одного пользователя могли быть полностью отделены от данных другого пользователя (и пользователь не мог обновлять данные другого пользователя ... и т. д.).

Хотя я могу получить имя пользователя, вошедшего в систему, у меня нет идентификатора пользователя.

Каков правильный подход к решению этой проблемы:

  • вызвать шлюз из микросервиса?

(для меня это не имеет особого смысла, поскольку шлюз вызывает службу, и я хочу знать эту информацию для большинства служб).

  • обновить TokenProvider в шлюзе, чтобы включить идентификатор пользователя? (не знаю, как это сделать). Это правильный подход?

  • любые другие предложения?

Спасибо, Фергал.

Примечание: я вижу другие похожие вопросы. Это не повторяющийся вопрос. Не отмечайте это как дубликат, если нет полной уверенности. Примечание. Я использую JWT.

Я бы обновил TokenProvider, заменив тему или добавив утверждение для идентификатора пользователя.

Gaël Marziou 31.10.2018 16:02

Спасибо @ GaëlMarziou. Я разместил свой код, чтобы он мог помочь другим. Любые отзывы о моем подходе приветствуются.

fergal_dd 01.11.2018 07:33

Хорошая работа. Спасибо, что опубликовали свой код .. Кстати, вы забыли "t" в Authenication в SamAuthenicationToken

Gaël Marziou 01.11.2018 11:44
5
3
1 232
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы решить эту проблему, я добавил идентификатор пользователя в токен от шлюза для каждого микросервиса.

Вот как я решил это в сгенерированном коде JHipster:

В шлюзе, добавьте UserService в UserJWTController и получите идентификатор пользователя, и используйте его при создании токена.

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 16.06.2020 11:35

@ddsultan - шлюз является наиболее подходящим местом для этого, поскольку это то, что нужно многим службам, стоящим за шлюзом. Если заставить шлюз делать это, каждая служба не должна делать себя сама ... как видите, это очень небольшое изменение для шлюза, но очень полезное. Я использовал ISAM (IBM Security and Access Mgt) в проекте, и их обратный прокси-сервер делает именно это.

fergal_dd 07.04.2021 10:59

@fergal_dd большое спасибо! Ваша реализация мне очень помогла !!!

Renan Franca 15.09.2021 16:48

Другие вопросы по теме