コアインターフェースとクラス
このセクションでは、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)
}
}
}
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 、password 、拡張認可型 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 レスポンスで返される属性の名前。 |
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
、password
認可付与型のサポートを提供する OAuth2AuthorizedClientProvider
コンポジットを構成および構築する方法の例を示しています。
Java
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.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()
.password()
.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
に必要な(サポートされている)属性を指定する必要がある場合に役立ちます。PasswordOAuth2AuthorizedClientProvider
では、リソース所有者の username
および password
が OAuth2AuthorizationContext.getAttributes()
で使用可能である必要があります。
次のコードは、contextAttributesMapper
の例を示しています。
Java
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` 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 username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME);
String password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = new HashMap<>();
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
}
return contextAttributes;
};
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
// Assuming the `username` and `password` 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 username: String = servletRequest.getParameter(OAuth2ParameterNames.USERNAME)
val password: String = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD)
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = hashMapOf()
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes[OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME] = username
contextAttributes[OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME] = password
}
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
}