Spring OAuth(OAuth2):如何在Spring MVC控制器中获取客户端凭据?

21

在以下代码片段中:

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

principal.getName() 提供了用户身份信息,但我需要一种方法来接收客户端凭据(客户端=>正在使用我的API的应用程序)。我该如何做到这一点?

6个回答

24

客户端身份可以从Authentication对象获取,您可以将其强制转换为主体,或直接从线程本地安全上下文中获取。例如:

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

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

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


2
不错的回答,只是帖子日期有点旧了。Spring Boot 1.3.3使用getOAuth2Request()而不是getAuthorizationRequest()。 - tao
客户端密钥呢? - Wafula Samuel

16

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

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

这个返回了主用户而不是客户端ID应用程序。 - Dimitri Kopriwa
2
更新版本:auth.getOAuth2Request().getClientId() - Cataclysm

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(对我来说,这是在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 {

}

0
一个简单的方法来检索clientId是通过加载当前已验证的principalprincipal可以直接定义为方法参数,并且框架将正确解析它。
以下是一个示例:
  @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;
  }

0

随着Spring OAuth的弃用, 其他一些答案不再适用。我使用以下代码在Spring Security 5中的AuthenticationSuccessHandler中获取clientId

@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;
}

0

还可以通过使用org.springframework.security.core.annotation.AuthenticationPrincipal注释来获取声明org.springframework.security.oauth2.jwt.Jwt对象。

@GetMapping
public String showClientId(@AuthenticationPrincipal Jwt principal) {
    return principal.getClaimAsString("clientId");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接