21

在这个片段中:

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

principal.getName()给了我用户标识,但我需要一种方法来接收客户端凭据(客户端 => 使用我的 API 的应用程序)。我怎样才能做到这一点?

4

6 回答 6

24

客户端身份可从Authentication您可以将主体投射到的对象中获得,或者直接从线程本地安全上下文中获取。就像是

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

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

如果您不想将该代码直接放入您的控制器中,则可以按照此答案中的描述实现一个单独的上下文访问器并将其注入其中。

于 2012-09-18T12:38:53.440 回答
16

我根据@luke-taylor 的回答找到了一个合理的解决方案。

@RequestMapping(method = GET)
public List<Place> read(OAuth2Authentication auth) {
  auth.getOAuth2Request().getClientId()
}
于 2012-09-26T19:12:17.220 回答
5

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我们的应用程序上下文中注册(对我来说这是在 a 中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 {

}
于 2015-02-02T18:57:26.287 回答
0

一种简单的检索方法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;
  }
于 2019-08-28T17:40:37.260 回答
0

也可以通过注释获得声明org.springframework.security.oauth2.jwt.Jwt对象。org.springframework.security.core.annotation.AuthenticationPrincipal

@GetMapping
public String showClientId(@AuthenticationPrincipal Jwt principal) {
    return principal.getClaimAsString("clientId");
}
于 2020-08-04T18:03:10.600 回答
0

随着spring-oauth 的弃用,其他一些答案不再起作用。我使用以下内容获得了clientIdspring AuthenticationSuccessHandler-security 5:

@Autowired
public OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository

protected String getClientId(final Authentication authentication, HttpServletRequest request) {
    OAuth2AuthenticationToken auth = (OAuth2AuthenticationToken) authentication;
    OAuth2AuthorizedClient client = oAuth2AuthorizedClientRepository.loadAuthorizedClient(auth.getAuthorizedClientRegistrationId(), auth, request);
    String clientId = client.getClientRegistration().getClientId();
    return clientId;
}
于 2021-11-11T14:18:58.450 回答