このスニペットの内容:
_@RequestMapping(method = GET)
public List<Place> read(Principal principal) {
principal.getName();
}
_
principal.getName()
はユーザーIDを提供しますが、クライアント資格情報を受け取る方法が必要です(client => APIを使用しているアプリ)。これどうやってするの?
@ luke-taylorの回答に基づいて合理的な解決策を見つけました。
@RequestMapping(method = GET)
public List<Place> read(OAuth2Authentication auth) {
auth.getOAuth2Request().getClientId()
}
クライアントIDは、プリンシパルをキャストするか、スレッドローカルセキュリティコンテキストから直接取得できるAuthentication
オブジェクトから取得できます。何かのようなもの
Authentication a = SecurityContextHolder.getContext().getAuthentication();
String clientId = ((OAuth2Authentication) a).getAuthorizationRequest().getClientId();
そのコードをコントローラーに直接配置したくない場合は、 この回答 で説明されているように、別のコンテキストアクセサーを実装し、代わりにそれを挿入することができます。
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;
}