OAuth 2.0 ベアラートークン
ベアラートークンの解決
デフォルトでは、リソースサーバーは Authorization
ヘッダーで無記名トークンを探します。ただし、これはいくつかの方法でカスタマイズできます。
カスタムヘッダーからベアラートークンを読み取る
例: カスタムヘッダーから無記名トークンを読み取る必要がある場合があります。これを実現するには、次の例に示すように、DefaultBearerTokenResolver
を Bean として公開するか、インスタンスを DSL に接続します。
Java
Kotlin
XML
@Bean
BearerTokenResolver bearerTokenResolver() {
DefaultBearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver();
bearerTokenResolver.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION);
return bearerTokenResolver;
}
@Bean
fun bearerTokenResolver(): BearerTokenResolver {
val bearerTokenResolver = DefaultBearerTokenResolver()
bearerTokenResolver.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION)
return bearerTokenResolver
}
<http>
<oauth2-resource-server bearer-token-resolver-ref="bearerTokenResolver"/>
</http>
<bean id="bearerTokenResolver"
class="org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver">
<property name="bearerTokenHeaderName" value="Proxy-Authorization"/>
</bean>
または、プロバイダーがカスタムヘッダーと値の両方を使用している状況では、代わりに HeaderBearerTokenResolver
を使用できます。
フォームパラメーターからベアラートークンを読み取る
または、以下に示すように、DefaultBearerTokenResolver
を構成することで実行できるフォームパラメーターからトークンを読み取ることもできます。
Java
Kotlin
XML
DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
resolver.setAllowFormEncodedBodyParameter(true);
http
.oauth2ResourceServer(oauth2 -> oauth2
.bearerTokenResolver(resolver)
);
val resolver = DefaultBearerTokenResolver()
resolver.setAllowFormEncodedBodyParameter(true)
http {
oauth2ResourceServer {
bearerTokenResolver = resolver
}
}
<http>
<oauth2-resource-server bearer-token-resolver-ref="bearerTokenResolver"/>
</http>
<bean id="bearerTokenResolver"
class="org.springframework.security.oauth2.server.resource.web.HeaderBearerTokenResolver">
<property name="allowFormEncodedBodyParameter" value="true"/>
</bean>
ベアラートークンの伝播
リソースサーバーがトークンを検証したため、それをダウンストリームサービスに渡すと便利な場合があります。これは ServletBearerExchangeFilterFunction (Javadoc)
を使用すると非常に簡単です。これは、次の例で確認できます。
Java
Kotlin
@Bean
public WebClient rest() {
return WebClient.builder()
.filter(new ServletBearerExchangeFilterFunction())
.build();
}
@Bean
fun rest(): WebClient {
return WebClient.builder()
.filter(ServletBearerExchangeFilterFunction())
.build()
}
上記の WebClient
を使用してリクエストを実行すると、Spring Security は現在の Authentication
を検索し、AbstractOAuth2Token (Javadoc)
資格情報を抽出します。次に、Authorization
ヘッダーでそのトークンを伝搬します。
例:
Java
Kotlin
this.rest.get()
.uri("https://other-service.example.com/endpoint")
.retrieve()
.bodyToMono(String.class)
.block()
this.rest.get()
.uri("https://other-service.example.com/endpoint")
.retrieve()
.bodyToMono<String>()
.block()
other-service.example.com/endpoint (英語)
を呼び出して、ベアラートークン Authorization
ヘッダーを追加します。
この動作をオーバーライドする必要がある場所では、次のようにヘッダーを自分で指定するだけです。
Java
Kotlin
this.rest.get()
.uri("https://other-service.example.com/endpoint")
.headers(headers -> headers.setBearerAuth(overridingToken))
.retrieve()
.bodyToMono(String.class)
.block()
this.rest.get()
.uri("https://other-service.example.com/endpoint")
.headers{ headers -> headers.setBearerAuth(overridingToken)}
.retrieve()
.bodyToMono<String>()
.block()
この場合、フィルターはフォールバックし、リクエストを Web フィルターチェーンの残りの部分に単純に転送します。
OAuth 2.0 クライアントフィルター機能 (Javadoc) とは異なり、このフィルター関数は、トークンが期限切れになった場合、トークンを更新しようとしません。このレベルのサポートを取得するには、OAuth 2.0 クライアントフィルターを使用してください。 |
RestTemplate
サポート
現在のところ、ServletBearerExchangeFilterFunction
に相当する RestTemplate
はありませんが、独自のインターセプターを使用して、リクエストのベアラートークンを非常に簡単に伝達できます。
Java
Kotlin
@Bean
RestTemplate rest() {
RestTemplate rest = new RestTemplate();
rest.getInterceptors().add((request, body, execution) -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return execution.execute(request, body);
}
if (!(authentication.getCredentials() instanceof AbstractOAuth2Token)) {
return execution.execute(request, body);
}
AbstractOAuth2Token token = (AbstractOAuth2Token) authentication.getCredentials();
request.getHeaders().setBearerAuth(token.getTokenValue());
return execution.execute(request, body);
});
return rest;
}
@Bean
fun rest(): RestTemplate {
val rest = RestTemplate()
rest.interceptors.add(ClientHttpRequestInterceptor { request, body, execution ->
val authentication: Authentication? = SecurityContextHolder.getContext().authentication
if (authentication == null) {
return execution.execute(request, body)
}
if (authentication.credentials !is AbstractOAuth2Token) {
return execution.execute(request, body)
}
request.headers.setBearerAuth(authentication.credentials.tokenValue)
execution.execute(request, body)
})
return rest
}
OAuth 2.0 承認済みクライアントマネージャー (Javadoc) とは異なり、このフィルターインターセプターは、トークンの有効期限が切れた場合にトークンを更新しようとしません。このレベルのサポートを取得するには、OAuth 2.0 承認済みクライアントマネージャーを使用してインターセプターを作成してください。 |
ベアラートークンエラー
ベアラートークンは、いくつかの理由で無効になる場合があります。例: トークンはアクティブではない可能性があります。
このような状況では、リソースサーバーは InvalidBearerTokenException
をスローします。他の例外と同様に、これにより OAuth 2.0 ベアラートークンエラーレスポンスが発生します。
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error_code="invalid_token", error_description="Unsupported algorithm of none", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
さらに、AuthenticationFailureBadCredentialsEvent
として公開されており、次のようにアプリケーションでリッスンできます。
Java
Kotlin
@Component
public class FailureEvents {
@EventListener
public void onFailure(AuthenticationFailureBadCredentialsEvent badCredentials) {
if (badCredentials.getAuthentication() instanceof BearerTokenAuthenticationToken) {
// ... handle
}
}
}
@Component
class FailureEvents {
@EventListener
fun onFailure(badCredentials: AuthenticationFailureBadCredentialsEvent) {
if (badCredentials.authentication is BearerTokenAuthenticationToken) {
// ... handle
}
}
}