在以下代码片段中:
@RequestMapping(method = GET)
public List<Place> read(Principal principal) {
principal.getName();
}
principal.getName()
提供了用户身份信息,但我需要一种方法来接收客户端凭据(客户端=>正在使用我的API的应用程序)。我该如何做到这一点?
在以下代码片段中:
@RequestMapping(method = GET)
public List<Place> read(Principal principal) {
principal.getName();
}
principal.getName()
提供了用户身份信息,但我需要一种方法来接收客户端凭据(客户端=>正在使用我的API的应用程序)。我该如何做到这一点?
客户端身份可以从Authentication
对象获取,您可以将其强制转换为主体,或直接从线程本地安全上下文中获取。例如:
Authentication a = SecurityContextHolder.getContext().getAuthentication();
String clientId = ((OAuth2Authentication) a).getAuthorizationRequest().getClientId();
如果您不想直接将那些代码放入您的控制器中,您可以按照这个答案中所述实现一个单独的上下文访问器,并将其注入到其中。
我根据@luke-taylor的回答找到了一个合理的解决方案。
@RequestMapping(method = GET)
public List<Place> read(OAuth2Authentication auth) {
auth.getOAuth2Request().getClientId()
}
auth.getOAuth2Request().getClientId()
- Cataclysm更详细地解释一下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 {
}
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;
}
随着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;
}
还可以通过使用org.springframework.security.core.annotation.AuthenticationPrincipal
注释来获取声明org.springframework.security.oauth2.jwt.Jwt
对象。
@GetMapping
public String showClientId(@AuthenticationPrincipal Jwt principal) {
return principal.getClaimAsString("clientId");
}