コアインターフェースとクラス
このセクションでは、Spring Security が提供する OAuth2 コアインターフェースとクラスについて説明します。
ClientRegistration
ClientRegistration は、OAuth 2.0 または OpenID Connect 1.0 プロバイダーに登録されたクライアントの表現です。
ClientRegistration オブジェクトは、クライアント ID、クライアントシークレット、認可付与型、リダイレクト URI、スコープ、認可 URI、トークン URI、その他の詳細などの情報を保持します。
ClientRegistration とそのプロパティは次のように定義されています。
public final class ClientRegistration {
private String registrationId; (1)
private String clientId; (2)
private String clientSecret; (3)
private ClientAuthenticationMethod clientAuthenticationMethod; (4)
private AuthorizationGrantType authorizationGrantType; (5)
private String redirectUri; (6)
private Set<String> scopes; (7)
private ProviderDetails providerDetails;
private String clientName; (8)
public class ProviderDetails {
private String authorizationUri; (9)
private String tokenUri; (10)
private UserInfoEndpoint userInfoEndpoint;
private String jwkSetUri; (11)
private String issuerUri; (12)
private Map<String, Object> configurationMetadata; (13)
public class UserInfoEndpoint {
private String uri; (14)
private AuthenticationMethod authenticationMethod; (15)
private String userNameAttributeName; (16)
}
}
public static final class ClientSettings {
private boolean requireProofKey; (17)
}
}| 1 | registrationId: ClientRegistration を一意に識別する ID。 |
| 2 | clientId: クライアント識別子。 |
| 3 | clientSecret: クライアントの秘密。 |
| 4 | clientAuthenticationMethod: プロバイダーでクライアントを認証するために使用される方法。サポートされている値は、client_secret_basic、client_secret_post、private_key_jwt、client_secret_jwt、および none (パブリッククライアント) [IETF] (英語) です。 |
| 5 | authorizationGrantType: OAuth 2.0 認可(フレームワーク)は、4 つの認可付与 [IETF] (英語) 型を定義します。サポートされる値は、authorization_code、client_credentials、拡張付与型 urn:ietf:params:oauth:grant-type:jwt-bearer です。 |
| 6 | redirectUri: エンドユーザーがクライアントへのアクセスを認証および認可した後に、認可サーバーがエンドユーザーのユーザーエージェントをリダイレクトするクライアントの登録済みリダイレクト URI。 |
| 7 | scopes: 認可リクエストフロー中にクライアントがリクエストしたスコープ(openid、メール、プロファイルなど)。 |
| 8 | clientName: クライアントに使用される説明的な名前。この名前は、自動生成されたログインページにクライアントの名前を表示するときなど、特定のシナリオで使用される場合があります。 |
| 9 | authorizationUri: 認可サーバーの認可エンドポイント URI。 |
| 10 | tokenUri: 認可サーバーのトークンエンドポイント URI。 |
| 11 | jwkSetUri: 認可サーバーから JSON Web キー (JWK) [IETF] (英語) セットを取得するために使用される URI。これには、ID トークンの JSON Web 署名 (JWS) [IETF] (英語) および(オプションで)UserInfo レスポンスを検証するために使用される暗号化キーが含まれます。 |
| 12 | issuerUri: OpenID Connect 1.0 プロバイダーまたは OAuth 2.0 認証サーバーの発行者 IDURI を返します。 |
| 13 | configurationMetadata: OpenID プロバイダーの構成情報 (英語) 。この情報は、Spring Boot プロパティ spring.security.oauth2.client.provider.[providerId].issuerUri が構成されている場合にのみ使用可能です。 |
| 14 | (userInfoEndpoint)uri: 認証されたエンドユーザーのクレームと属性にアクセスするために使用される UserInfo エンドポイント URI。 |
| 15 | (userInfoEndpoint)authenticationMethod: アクセストークンを UserInfo エンドポイントに送信するときに使用される認証方法。サポートされている値は、header、form、および query です。 |
| 16 | userNameAttributeName: エンドユーザーの名前または識別子を参照する UserInfo レスポンスで返される属性の名前。 |
| 17 | requireProofKey: true の場合、または clientAuthenticationMethod が none の場合、PKCE が有効になります。 |
OpenID Connect プロバイダーの構成エンドポイント (英語) または認可サーバーのメタデータエンドポイント [IETF] (英語) の検出を使用して、最初に ClientRegistration を構成できます。
ClientRegistrations は、次のように ClientRegistration を構成するための便利なメソッドを提供します。
Java
Kotlin
ClientRegistration clientRegistration =
ClientRegistrations.fromIssuerLocation("https://idp.example.com/issuer").build();
val clientRegistration = ClientRegistrations.fromIssuerLocation("https://idp.example.com/issuer").build()
上記のコードは、idp.example.com/issuer/.well-known/openid-configuration (英語) 、idp.example.com/.well-known/openid-configuration/issuer (英語) 、idp.example.com/.well-known/oauth-authorization-server/issuer (英語) を直列にクエリし、最初に停止して 200 レスポンスを返します。
別の方法として、ClientRegistrations.fromOidcIssuerLocation() を使用して、OpenIDConnect プロバイダーの構成エンドポイントのみを照会できます。
ClientRegistrationRepository
ClientRegistrationRepository は、OAuth 2.0/OpenID Connect 1.0 ClientRegistration のリポジトリとして機能します。
クライアント登録情報は、最終的には関連する認証サーバーによって保存および所有されます。このリポジトリは、認可サーバーとともに保管されている 1 次クライアント登録情報のサブセットを取得する機能を提供します。 |
Spring Boot 自動構成は、spring.security.oauth2.client.registration.[registrationId] の各プロパティを ClientRegistration のインスタンスにバインドし、ClientRegistrationRepository 内の各 ClientRegistration インスタンスを構成します。
|
自動構成では、ClientRegistrationRepository が ApplicationContext に @Bean として登録されるため、アプリケーションで必要な場合は、依存性注入に使用できます。
次のリストに例を示します。
Java
Kotlin
@Controller
public class OAuth2ClientController {
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@GetMapping("/")
public String index() {
ClientRegistration oktaRegistration =
this.clientRegistrationRepository.findByRegistrationId("okta");
...
return "index";
}
}
@Controller
class OAuth2ClientController {
@Autowired
private lateinit var clientRegistrationRepository: ClientRegistrationRepository
@GetMapping("/")
fun index(): String {
val oktaRegistration =
this.clientRegistrationRepository.findByRegistrationId("okta")
//...
return "index";
}
}
OAuth2AuthorizedClient
OAuth2AuthorizedClient は、認可されたクライアントの表現です。エンドユーザー(リソース所有者)がクライアントに保護されたリソースへのアクセスを認可した場合、クライアントは認可されていると見なされます。
OAuth2AuthorizedClient は、OAuth2AccessToken (およびオプションの OAuth2RefreshToken)を、認可を認可した Principal エンドユーザーである ClientRegistration (クライアント)およびリソース所有者に関連付ける目的に役立ちます。
OAuth2AuthorizedClientRepository および OAuth2AuthorizedClientService
OAuth2AuthorizedClientRepository は、Web リクエスト間で OAuth2AuthorizedClient を永続化するロールを果たしますが、OAuth2AuthorizedClientService の主なロールは、アプリケーションレベルで OAuth2AuthorizedClient を管理することです。
開発者の観点からは、OAuth2AuthorizedClientRepository または OAuth2AuthorizedClientService は、クライアントに関連付けられた OAuth2AccessToken を検索する機能を提供し、保護されたリソースリクエストを開始するために使用できるようにします。
次のリストに例を示します。
Java
Kotlin
@Controller
public class OAuth2ClientController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@GetMapping("/")
public String index(Authentication authentication) {
OAuth2AuthorizedClient authorizedClient =
this.authorizedClientService.loadAuthorizedClient("okta", authentication.getName());
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "index";
}
}
@Controller
class OAuth2ClientController {
@Autowired
private lateinit var authorizedClientService: OAuth2AuthorizedClientService
@GetMapping("/")
fun index(authentication: Authentication): String {
val authorizedClient: OAuth2AuthorizedClient =
this.authorizedClientService.loadAuthorizedClient("okta", authentication.getName());
val accessToken = authorizedClient.accessToken
...
return "index";
}
}
Spring Boot 自動構成は、 |
OAuth2AuthorizedClientService のデフォルトの実装は InMemoryOAuth2AuthorizedClientService で、OAuth2AuthorizedClient オブジェクトをメモリに格納します。
または、データベースに OAuth2AuthorizedClient インスタンスを永続化するように JDBC 実装 JdbcOAuth2AuthorizedClientService を構成することもできます。
|
OAuth2AuthorizedClientManager および OAuth2AuthorizedClientProvider
OAuth2AuthorizedClientManager は、OAuth2AuthorizedClient の全体的な管理を担当します。
主な責務は次のとおりです。
OAuth2AuthorizedClientProviderを使用して、OAuth 2.0 クライアントを承認(または再承認)します。通常、
OAuth2AuthorizedClientServiceまたはOAuth2AuthorizedClientRepositoryを使用して、OAuth2AuthorizedClientの永続性を委譲します。OAuth 2.0 クライアントが正常に認証(または再認証)された場合、
OAuth2AuthorizationSuccessHandlerに委譲します。OAuth 2.0 クライアントが認証(または再認証)に失敗した場合の
OAuth2AuthorizationFailureHandlerへの委譲。
OAuth2AuthorizedClientProvider は、OAuth 2.0 クライアントを認可(または再認可)するための戦略を実装します。実装は通常、authorization_code、client_credentials などの認可付与型を実装します。
OAuth2AuthorizedClientManager のデフォルトの実装は DefaultOAuth2AuthorizedClientManager です。これは、委譲ベースのコンポジットを使用して複数の認可付与型をサポートする可能性のある OAuth2AuthorizedClientProvider に関連付けられています。OAuth2AuthorizedClientProviderBuilder を使用して、委譲ベースのコンポジットを構成および構築できます。
次のコードは、authorization_code、refresh_token、client_credentials 認可付与型のサポートを提供する OAuth2AuthorizedClientProvider コンポジットを構成および構築する方法の例を示しています。
Java
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}
認可の試行が成功すると、DefaultOAuth2AuthorizedClientManager は OAuth2AuthorizationSuccessHandler に委譲します。これにより、(デフォルトで) OAuth2AuthorizedClientRepository を介して OAuth2AuthorizedClient が保存されます。再認証に失敗した場合(たとえば、リフレッシュトークンが無効になった場合)、以前に保存された OAuth2AuthorizedClient は、RemoveAuthorizedClientOAuth2AuthorizationFailureHandler を介して OAuth2AuthorizedClientRepository から削除されます。setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler) および setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler) を使用してデフォルトの動作をカスタマイズできます。
DefaultOAuth2AuthorizedClientManager は、Function<OAuth2AuthorizeRequest, Map<String, Object>> 型の contextAttributesMapper にも関連付けられています。Function<OAuth2AuthorizeRequest, Map<String, Object>> 型は、OAuth2AuthorizeRequest の属性を OAuth2AuthorizationContext に関連付ける Map の属性にマッピングするロールを担います。これは、OAuth2AuthorizedClientProvider に必要な(サポートされている)属性を指定する必要がある場合に役立ちます。
次のコードは、contextAttributesMapper の例を示しています。
Java
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the attributes are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
return authorizedClientManager;
}
private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributesMapper() {
return authorizeRequest -> {
Map<String, Object> contextAttributes = Collections.emptyMap();
HttpServletRequest servletRequest = authorizeRequest.getAttribute(HttpServletRequest.class.getName());
String param1 = servletRequest.getParameter("param1");
String param2 = servletRequest.getParameter("param2");
if (StringUtils.hasText(param1) && StringUtils.hasText(param2)) {
contextAttributes = new HashMap<>();
contextAttributes.put("param1", param1);
contextAttributes.put("param2", param2);
}
return contextAttributes;
};
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
// Assuming the attributes are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper())
return authorizedClientManager
}
private fun contextAttributesMapper(): Function<OAuth2AuthorizeRequest, MutableMap<String, Any>> {
return Function { authorizeRequest ->
var contextAttributes: MutableMap<String, Any> = mutableMapOf()
val servletRequest: HttpServletRequest = authorizeRequest.getAttribute(HttpServletRequest::class.java.name)
val param1: String = servletRequest.getParameter("param1")
val param2: String = servletRequest.getParameter("param2")
if (StringUtils.hasText(param1) && StringUtils.hasText(param2)) {
contextAttributes = hashMapOf()
contextAttributes["param1"] = param1
contextAttributes["param2"] = param2
}
contextAttributes
}
}
DefaultOAuth2AuthorizedClientManager は、HttpServletRequest のコンテキスト内で使用するように設計されています。HttpServletRequest コンテキストの外部で操作する場合は、代わりに AuthorizedClientServiceOAuth2AuthorizedClientManager を使用してください。
サービスアプリケーションは、AuthorizedClientServiceOAuth2AuthorizedClientManager をいつ使用するかについての一般的な使用例です。多くの場合、サービスアプリケーションはユーザーの操作なしでバックグラウンドで実行され、通常はユーザーアカウントではなくシステムレベルのアカウントで実行されます。client_credentials 付与型で構成された OAuth 2.0 クライアントは、サービスアプリケーションの型と見なすことができます。
次のコードは、client_credentials 付与型のサポートを提供する AuthorizedClientServiceOAuth2AuthorizedClientManager を構成する方法の例を示しています。
Java
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService authorizedClientService) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientService: OAuth2AuthorizedClientService): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build()
val authorizedClientManager = AuthorizedClientServiceOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}