Подтвердить что ты не робот

Spring OAuth (OAuth2): Как я могу получить учетные данные клиента в контроллере MVC Spring?

В этом фрагменте:

@RequestMapping(method = GET)
public List<Place> read(Principal principal) {
  principal.getName(); 
}

principal.getName() дает мне идентификатор пользователя, но мне нужен способ получения учетных данных клиента (client = > приложение, использующее мой API). Как я могу это сделать?

4b9b3361

Ответ 1

Я нашел разумное решение, основанное на ответе @luke-taylor.

@RequestMapping(method = GET)
public List<Place> read(OAuth2Authentication auth) {
  auth.getOAuth2Request().getClientId()
}

Ответ 2

Идентификатор клиента доступен из объекта Authentication, который вы можете либо передать принципалу, либо получить непосредственно из локального контекста безопасности потока. Что-то вроде

Authentication a = SecurityContextHolder.getContext().getAuthentication();

String clientId = ((OAuth2Authentication) a).getAuthorizationRequest().getClientId();

Если вы не хотите размещать этот код непосредственно в своем контроллере, вы можете реализовать отдельный контекстный аксессор, как описано в этом ответе, и вместо этого ввести его в него.

Ответ 3

Разверните параметр HandlerMethodArgumentResolver немного больше. Чтобы поддержать следующее:

@RequestMapping(
    value = WEB_HOOKS, 
    method = RequestMethod.GET, 
    produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public List<SomeDTO> getThoseDTOs(@CurrentClientId String clientId) 
{
    // Do something with clientId - it will be null if there was no authentication
}

Нам понадобится HandlerMethodArgumentResolver, зарегистрированный в нашем контексте приложения (для меня это было внутри WebMvcConfigurerAdapter). Мой HandlerMethodArgumentResolver выглядит следующим образом:

public class OAuth2ClientIdArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(CurrentClientId.class) != null
                && parameter.getParameterType().equals(String.class);
    }

    @Override
    public Object resolveArgument(
            MethodParameter parameter,
            ModelAndViewContainer mavContainer, 
            NativeWebRequest webRequest,
            WebDataBinderFactory binderFactory) 
        throws Exception 
    {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication == null) {
            return null;
        }
        String clientId = null;

        if (authentication.getClass().isAssignableFrom(OAuth2Authentication.class)) {
            clientId = ((OAuth2Authentication) authentication).getOAuth2Request().getClientId();
        }

        return clientId;
    }

}

И определение @interface:

@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurrentClientId {

}

Ответ 4

Простой способ получить clientId - загрузить аутентифицированный в настоящее время principal. principal может быть определен непосредственно как аргумент метода, и он будет правильно разрешен платформой.

Вот пример:

  @RequestMapping(method = RequestMethod.GET)
  public Map<String, String> getUserInfo(Principal principal) {
    OAuth2Authentication oauth = (OAuth2Authentication) principal;

    Map<String, String> userInfo = new LinkedHashMap<>();
    userInfo.put("username", principal.getName());
    userInfo.put("clientId", oauth.getOAuth2Request().getClientId());
    return userInfo;
  }