授權許可支援
本節描述 Spring Security 對授權許可的支援。
授權碼
|
有關授權碼許可的更多詳細資訊,請參閱 OAuth 2.0 授權框架。 |
獲取授權
|
有關授權碼許可的授權請求/響應協議流,請參閱。 |
啟動授權請求
OAuth2AuthorizationRequestRedirectFilter 使用 OAuth2AuthorizationRequestResolver 解析 OAuth2AuthorizationRequest 並透過將終端使用者的使用者代理重定向到授權伺服器的授權端點來啟動授權碼許可流。
OAuth2AuthorizationRequestResolver 的主要作用是從提供的 Web 請求中解析 OAuth2AuthorizationRequest。預設實現 DefaultOAuth2AuthorizationRequestResolver 匹配(預設)路徑 /oauth2/authorization/{registrationId},提取 registrationId,並使用它為關聯的 ClientRegistration 構建 OAuth2AuthorizationRequest。
考慮以下 OAuth 2.0 客戶端註冊的 Spring Boot 屬性
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/authorized/okta"
scope: read, write
provider:
okta:
authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize
token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
鑑於前面的屬性,具有基本路徑 /oauth2/authorization/okta 的請求會由 OAuth2AuthorizationRequestRedirectFilter 啟動授權請求重定向,並最終啟動授權碼許可流。
|
|
如果 OAuth 2.0 客戶端是公共客戶端,請按如下方式配置 OAuth 2.0 客戶端註冊
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-authentication-method: none
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/authorized/okta"
# ...
透過使用授權碼交換的證明金鑰(PKCE)來支援公共客戶端。如果客戶端在不受信任的環境中執行(例如原生應用程式或基於 Web 瀏覽器的應用程式),因此無法維護其憑據的機密性,則在以下條件為真時會自動使用 PKCE
-
client-secret被省略(或為空)並且 -
client-authentication-method設定為none(ClientAuthenticationMethod.NONE)
或
-
當
ClientRegistration.clientSettings.requireProofKey為true時(在這種情況下ClientRegistration.authorizationGrantType必須是authorization_code)
|
如果 OAuth 2.0 提供者支援機密客戶端的 PKCE,您可以(可選地)使用 |
以下配置使用所有支援的 URI 模板變數
spring:
security:
oauth2:
client:
registration:
okta:
# ...
redirect-uri: "{baseScheme}://{baseHost}{basePort}{basePath}/authorized/{registrationId}"
# ...
|
|
使用 URI 模板變數配置 redirect-uri 在 OAuth 2.0 客戶端在代理伺服器後面執行時特別有用。這樣做可以確保在擴充套件 redirect-uri 時使用 X-Forwarded-* 標頭。
自定義授權請求
OAuth2AuthorizationRequestResolver 可以實現的主要用例之一是能夠使用 OAuth 2.0 授權框架中定義的標準引數之外的附加引數來定製授權請求。
例如,OpenID Connect 為授權碼流定義了額外的 OAuth 2.0 請求引數,這些引數擴充套件自OAuth 2.0 授權框架中定義的標準引數。其中一個擴充套件引數是 prompt 引數。
|
|
以下示例演示如何使用 Consumer<OAuth2AuthorizationRequest.Builder> 配置 DefaultOAuth2AuthorizationRequestResolver,該 Consumer<OAuth2AuthorizationRequest.Builder> 透過包含請求引數 prompt=consent 來為 oauth2Login() 定製授權請求。
-
Java
-
Kotlin
@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2Login((oauth2) -> oauth2
.authorizationEndpoint((authorization) -> authorization
.authorizationRequestResolver(
authorizationRequestResolver(this.clientRegistrationRepository)
)
)
);
return http.build();
}
private OAuth2AuthorizationRequestResolver authorizationRequestResolver(
ClientRegistrationRepository clientRegistrationRepository) {
DefaultOAuth2AuthorizationRequestResolver authorizationRequestResolver =
new DefaultOAuth2AuthorizationRequestResolver(
clientRegistrationRepository, "/oauth2/authorization");
authorizationRequestResolver.setAuthorizationRequestCustomizer(
authorizationRequestCustomizer());
return authorizationRequestResolver;
}
private Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() {
return customizer -> customizer
.additionalParameters((params) -> params.put("prompt", "consent"));
}
}
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Autowired
private lateinit var customClientRegistrationRepository: ClientRegistrationRepository
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize(anyRequest, authenticated)
}
oauth2Login {
authorizationEndpoint {
authorizationRequestResolver = authorizationRequestResolver(customClientRegistrationRepository)
}
}
}
return http.build()
}
private fun authorizationRequestResolver(
clientRegistrationRepository: ClientRegistrationRepository?): OAuth2AuthorizationRequestResolver {
val authorizationRequestResolver = DefaultOAuth2AuthorizationRequestResolver(
clientRegistrationRepository, "/oauth2/authorization")
authorizationRequestResolver.setAuthorizationRequestCustomizer(
authorizationRequestCustomizer())
return authorizationRequestResolver
}
private fun authorizationRequestCustomizer(): Consumer<OAuth2AuthorizationRequest.Builder> {
return Consumer { customizer ->
customizer
.additionalParameters { params -> params["prompt"] = "consent" }
}
}
}
對於特定提供者,如果附加請求引數始終相同,則可以直接在 authorization-uri 屬性中新增它。
例如,如果提供者 okta 的請求引數 prompt 的值始終是 consent,您可以按如下方式配置它
spring:
security:
oauth2:
client:
provider:
okta:
authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize?prompt=consent
前面的示例展示了在標準引數之上新增自定義引數的常見用例。或者,如果您的要求更高階,您可以透過覆蓋 OAuth2AuthorizationRequest.authorizationRequestUri 屬性來完全控制構建授權請求 URI。
|
|
以下示例顯示了前面示例中 authorizationRequestCustomizer() 的變體,並改為覆蓋 OAuth2AuthorizationRequest.authorizationRequestUri 屬性
-
Java
-
Kotlin
private Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() {
return customizer -> customizer
.authorizationRequestUri((uriBuilder) -> uriBuilder
.queryParam("prompt", "consent").build());
}
private fun authorizationRequestCustomizer(): Consumer<OAuth2AuthorizationRequest.Builder> {
return Consumer { customizer: OAuth2AuthorizationRequest.Builder ->
customizer
.authorizationRequestUri { uriBuilder: UriBuilder ->
uriBuilder
.queryParam("prompt", "consent").build()
}
}
}
儲存授權請求
AuthorizationRequestRepository 負責從授權請求啟動到接收授權響應(回撥)期間 OAuth2AuthorizationRequest 的持久化。
|
|
AuthorizationRequestRepository 的預設實現是 HttpSessionOAuth2AuthorizationRequestRepository,它將 OAuth2AuthorizationRequest 儲存在 HttpSession 中。
如果您有 AuthorizationRequestRepository 的自定義實現,您可以按如下方式配置它
-
Java
-
Kotlin
-
Xml
@Configuration
@EnableWebSecurity
public class OAuth2ClientSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Client((oauth2) -> oauth2
.authorizationCodeGrant((codeGrant) -> codeGrant
.authorizationRequestRepository(this.authorizationRequestRepository())
// ...
)
)
.oauth2Login((oauth2) -> oauth2
.authorizationEndpoint((endpoint) -> endpoint
.authorizationRequestRepository(this.authorizationRequestRepository())
// ...
)
);
return http.build();
}
@Bean
public AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository() {
return new CustomOAuth2AuthorizationRequestRepository();
}
}
@Configuration
@EnableWebSecurity
class OAuth2ClientSecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
oauth2Client {
authorizationCodeGrant {
authorizationRequestRepository = authorizationRequestRepository()
}
}
}
return http.build()
}
}
<http>
<oauth2-client>
<authorization-code-grant authorization-request-repository-ref="authorizationRequestRepository"/>
</oauth2-client>
</http>
請求訪問令牌
|
有關授權碼許可的訪問令牌請求/響應協議流,請參閱。 |
授權碼許可的 OAuth2AccessTokenResponseClient 的預設實現是 RestClientAuthorizationCodeTokenResponseClient,它使用 RestClient 例項在授權伺服器的令牌端點交換授權碼以獲取訪問令牌。
RestClientAuthorizationCodeTokenResponseClient 非常靈活,並提供了多種選項來定製授權碼許可的 OAuth 2.0 訪問令牌請求和響應。從以下用例中選擇以瞭解更多資訊
-
我希望定製訪問令牌請求的標頭
-
我希望定製訪問令牌請求的引數
-
我希望定製訪問令牌響應的引數
定製訪問令牌請求
RestClientAuthorizationCodeTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌請求的 HTTP 標頭和請求引數的鉤子。
定製請求標頭
有兩種定製 HTTP 標頭的選項
-
透過呼叫
addHeadersConverter()新增額外的標頭 -
透過呼叫
setHeadersConverter()完全定製標頭
您可以使用 addHeadersConverter() 包含額外的標頭,而不會影響新增到每個請求的預設標頭。以下示例在 registrationId 為 spring 時向請求新增 User-Agent 標頭
-
Java
-
Kotlin
RestClientAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new RestClientAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.addHeadersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
HttpHeaders headers = new HttpHeaders();
if (clientRegistration.getRegistrationId().equals("spring")) {
headers.set(HttpHeaders.USER_AGENT, "my-user-agent");
}
return headers;
});
val accessTokenResponseClient = RestClientAuthorizationCodeTokenResponseClient()
accessTokenResponseClient.addHeadersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val headers = HttpHeaders()
if (clientRegistration.getRegistrationId() == "spring") {
headers[HttpHeaders.USER_AGENT] = "my-user-agent"
}
headers
}
您可以透過重新使用 DefaultOAuth2TokenRequestHeadersConverter 或使用 setHeadersConverter() 提供自定義實現來完全定製標頭。以下示例重新使用 DefaultOAuth2TokenRequestHeadersConverter 並停用 encodeClientCredentials,以便 HTTP Basic 憑據不再使用 application/x-www-form-urlencoded 進行編碼
-
Java
-
Kotlin
DefaultOAuth2TokenRequestHeadersConverter headersConverter =
new DefaultOAuth2TokenRequestHeadersConverter();
headersConverter.setEncodeClientCredentials(false);
RestClientAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new RestClientAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setHeadersConverter(headersConverter);
val headersConverter = DefaultOAuth2TokenRequestHeadersConverter()
headersConverter.setEncodeClientCredentials(false)
val accessTokenResponseClient = RestClientAuthorizationCodeTokenResponseClient()
accessTokenResponseClient.setHeadersConverter(headersConverter)
定製請求引數
有三種定製請求引數的選項
-
透過呼叫
addParametersConverter()新增額外引數 -
透過呼叫
setParametersConverter()覆蓋引數 -
透過呼叫
setParametersCustomizer()完全定製引數
|
使用 |
您可以使用 addParametersConverter() 包含額外的引數,而不會影響新增到每個請求的預設引數。以下示例在 registrationId 為 keycloak 時向請求新增 audience 引數
-
Java
-
Kotlin
RestClientAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new RestClientAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.addParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
if (clientRegistration.getRegistrationId().equals("keycloak")) {
parameters.set(OAuth2ParameterNames.AUDIENCE, "my-audience");
}
return parameters;
});
val accessTokenResponseClient = RestClientAuthorizationCodeTokenResponseClient()
accessTokenResponseClient.addParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "keycloak") {
parameters[OAuth2ParameterNames.AUDIENCE] = "my-audience"
}
parameters
}
您可以使用 setParametersConverter() 覆蓋預設引數。以下示例在 registrationId 為 okta 時覆蓋 client_id 引數
-
Java
-
Kotlin
RestClientAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new RestClientAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
LinkedMultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
if (clientRegistration.getRegistrationId().equals("okta")) {
parameters.set(OAuth2ParameterNames.CLIENT_ID, "my-client");
}
return parameters;
});
val parametersConverter = DefaultOAuth2TokenRequestParametersConverter<OAuth2AuthorizationCodeGrantRequest>()
parametersConverter.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
val accessTokenResponseClient = RestClientAuthorizationCodeTokenResponseClient()
accessTokenResponseClient.setParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "okta") {
parameters[OAuth2ParameterNames.CLIENT_ID] = "my-client"
}
parameters
}
您可以使用 setParametersCustomizer() 完全定製引數(包括省略預設引數)。以下示例在請求中存在 client_assertion 引數時省略 client_id 引數
-
Java
-
Kotlin
RestClientAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new RestClientAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setParametersCustomizer(parameters -> {
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID);
}
});
val accessTokenResponseClient = RestClientAuthorizationCodeTokenResponseClient()
accessTokenResponseClient.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
定製訪問令牌響應
RestClientAuthorizationCodeTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌響應的響應引數和錯誤處理的鉤子。
定製 RestClient
您可以透過向 setRestClient() 提供預配置的 RestClient 來定製令牌響應。預設的 RestClient 配置如下
RestClient 配置-
Java
-
Kotlin
RestClient restClient = RestClient.builder()
.messageConverters(messageConverters -> {
messageConverters.clear();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter());
})
.defaultStatusHandler(new OAuth2ErrorResponseErrorHandler())
.build();
RestClientAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new RestClientAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRestClient(restClient);
val restClient = RestClient.builder()
.messageConverters { messageConverters ->
messageConverters.clear()
messageConverters.add(FormHttpMessageConverter())
messageConverters.add(OAuth2AccessTokenResponseHttpMessageConverter())
}
.defaultStatusHandler(OAuth2ErrorResponseErrorHandler())
.build()
val accessTokenResponseClient = RestClientAuthorizationCodeTokenResponseClient()
accessTokenResponseClient.setRestClient(restClient)
OAuth2AccessTokenResponseHttpMessageConverter 是 OAuth 2.0 訪問令牌響應的 HttpMessageConverter。您可以透過呼叫 setAccessTokenResponseConverter() 定製令牌響應引數到 OAuth2AccessTokenResponse 的轉換。預設實現是 DefaultMapOAuth2AccessTokenResponseConverter。
OAuth2ErrorResponseErrorHandler 是一個 ResponseErrorHandler,可以處理 OAuth 2.0 錯誤,例如 400 Bad Request。它使用 OAuth2ErrorHttpMessageConverter 將 OAuth 2.0 錯誤引數轉換為 OAuth2Error。您可以透過呼叫 setErrorConverter() 定製令牌響應引數到 OAuth2Error 的轉換。
|
Spring MVC |
定製響應引數
以下示例提供了定製令牌響應引數到 OAuth2AccessTokenResponse 轉換的起點
-
Java
-
Kotlin
OAuth2AccessTokenResponseHttpMessageConverter accessTokenResponseMessageConverter =
new OAuth2AccessTokenResponseHttpMessageConverter();
accessTokenResponseMessageConverter.setAccessTokenResponseConverter(parameters -> {
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build();
});
val accessTokenResponseMessageConverter = OAuth2AccessTokenResponseHttpMessageConverter()
accessTokenResponseMessageConverter.setAccessTokenResponseConverter { parameters ->
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build()
}
定製錯誤處理
以下示例提供了定製錯誤引數到 OAuth2Error 轉換的起點
-
Java
-
Kotlin
OAuth2ErrorHttpMessageConverter errorConverter =
new OAuth2ErrorHttpMessageConverter();
errorConverter.setErrorConverter(parameters -> {
// ...
return new OAuth2Error("custom-error", "custom description", "custom-uri");
});
OAuth2ErrorResponseErrorHandler errorHandler =
new OAuth2ErrorResponseErrorHandler();
errorHandler.setErrorConverter(errorConverter);
val errorConverter = OAuth2ErrorHttpMessageConverter()
errorConverter.setErrorConverter { parameters ->
// ...
return OAuth2Error("custom-error", "custom description", "custom-uri")
}
val errorHandler = OAuth2ErrorResponseErrorHandler()
errorHandler.setErrorConverter(errorConverter)
使用 DSL 定製
無論您是定製 RestClientAuthorizationCodeTokenResponseClient 還是提供自己的 OAuth2AccessTokenResponseClient 實現,您都可以使用 DSL 進行配置(作為釋出 bean 的替代方案),如下所示
-
Java
-
Kotlin
-
Xml
@Configuration
@EnableWebSecurity
public class OAuth2ClientSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Client((oauth2) -> oauth2
.authorizationCodeGrant((codeGrant) -> codeGrant
.accessTokenResponseClient(this.accessTokenResponseClient())
// ...
)
);
return http.build();
}
}
@Configuration
@EnableWebSecurity
class OAuth2ClientSecurityConfig {
@Bean
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
oauth2Client {
authorizationCodeGrant {
accessTokenResponseClient = accessTokenResponseClient()
}
}
}
return http.build()
}
}
<http>
<oauth2-client>
<authorization-code-grant access-token-response-client-ref="accessTokenResponseClient"/>
</oauth2-client>
</http>
重新整理令牌
|
有關重新整理令牌的更多詳細資訊,請參閱 OAuth 2.0 授權框架。 |
重新整理訪問令牌
|
有關重新整理令牌許可的訪問令牌請求/響應協議流,請參閱。 |
重新整理令牌許可的 OAuth2AccessTokenResponseClient 的預設實現是 RestClientRefreshTokenTokenResponseClient,它使用 RestClient 例項在授權伺服器的令牌端點獲取訪問令牌。
RestClientRefreshTokenTokenResponseClient 非常靈活,並提供了多種選項來定製重新整理令牌許可的 OAuth 2.0 訪問令牌請求和響應。從以下用例中選擇以瞭解更多資訊
-
我希望定製訪問令牌請求的標頭
-
我希望定製訪問令牌請求的引數
-
我希望定製訪問令牌響應的引數
定製訪問令牌請求
RestClientRefreshTokenTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌請求的 HTTP 標頭和請求引數的鉤子。
定製請求標頭
有兩種定製 HTTP 標頭的選項
-
透過呼叫
addHeadersConverter()新增額外的標頭 -
透過呼叫
setHeadersConverter()完全定製標頭
您可以使用 addHeadersConverter() 包含額外的標頭,而不會影響新增到每個請求的預設標頭。以下示例在 registrationId 為 spring 時向請求新增 User-Agent 標頭
-
Java
-
Kotlin
RestClientRefreshTokenTokenResponseClient accessTokenResponseClient =
new RestClientRefreshTokenTokenResponseClient();
accessTokenResponseClient.addHeadersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
HttpHeaders headers = new HttpHeaders();
if (clientRegistration.getRegistrationId().equals("spring")) {
headers.set(HttpHeaders.USER_AGENT, "my-user-agent");
}
return headers;
});
val accessTokenResponseClient = RestClientRefreshTokenTokenResponseClient()
accessTokenResponseClient.addHeadersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val headers = HttpHeaders()
if (clientRegistration.getRegistrationId() == "spring") {
headers[HttpHeaders.USER_AGENT] = "my-user-agent"
}
headers
}
您可以透過重新使用 DefaultOAuth2TokenRequestHeadersConverter 或使用 setHeadersConverter() 提供自定義實現來完全定製標頭。以下示例重新使用 DefaultOAuth2TokenRequestHeadersConverter 並停用 encodeClientCredentials,以便 HTTP Basic 憑據不再使用 application/x-www-form-urlencoded 進行編碼
-
Java
-
Kotlin
DefaultOAuth2TokenRequestHeadersConverter headersConverter =
new DefaultOAuth2TokenRequestHeadersConverter();
headersConverter.setEncodeClientCredentials(false);
RestClientRefreshTokenTokenResponseClient accessTokenResponseClient =
new RestClientRefreshTokenTokenResponseClient();
accessTokenResponseClient.setHeadersConverter(headersConverter);
val headersConverter = DefaultOAuth2TokenRequestHeadersConverter()
headersConverter.setEncodeClientCredentials(false)
val accessTokenResponseClient = RestClientRefreshTokenTokenResponseClient()
accessTokenResponseClient.setHeadersConverter(headersConverter)
定製請求引數
有三種定製請求引數的選項
-
透過呼叫
addParametersConverter()新增額外引數 -
透過呼叫
setParametersConverter()覆蓋引數 -
透過呼叫
setParametersCustomizer()完全定製引數
|
使用 |
您可以使用 addParametersConverter() 包含額外的引數,而不會影響新增到每個請求的預設引數。以下示例在 registrationId 為 keycloak 時向請求新增 audience 引數
-
Java
-
Kotlin
RestClientRefreshTokenTokenResponseClient accessTokenResponseClient =
new RestClientRefreshTokenTokenResponseClient();
accessTokenResponseClient.addParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
if (clientRegistration.getRegistrationId().equals("keycloak")) {
parameters.set(OAuth2ParameterNames.AUDIENCE, "my-audience");
}
return parameters;
});
val accessTokenResponseClient = RestClientRefreshTokenTokenResponseClient()
accessTokenResponseClient.addParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "keycloak") {
parameters[OAuth2ParameterNames.AUDIENCE] = "my-audience"
}
parameters
}
您可以使用 setParametersConverter() 覆蓋預設引數。以下示例在 registrationId 為 okta 時覆蓋 client_id 引數
-
Java
-
Kotlin
RestClientRefreshTokenTokenResponseClient accessTokenResponseClient =
new RestClientRefreshTokenTokenResponseClient();
accessTokenResponseClient.setParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
LinkedMultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
if (clientRegistration.getRegistrationId().equals("okta")) {
parameters.set(OAuth2ParameterNames.CLIENT_ID, "my-client");
}
return parameters;
});
val parametersConverter = DefaultOAuth2TokenRequestParametersConverter<OAuth2RefreshTokenGrantRequest>()
parametersConverter.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
val accessTokenResponseClient = RestClientRefreshTokenTokenResponseClient()
accessTokenResponseClient.setParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "okta") {
parameters[OAuth2ParameterNames.CLIENT_ID] = "my-client"
}
parameters
}
您可以使用 setParametersCustomizer() 完全定製引數(包括省略預設引數)。以下示例在請求中存在 client_assertion 引數時省略 client_id 引數
-
Java
-
Kotlin
RestClientRefreshTokenTokenResponseClient accessTokenResponseClient =
new RestClientRefreshTokenTokenResponseClient();
accessTokenResponseClient.setParametersCustomizer(parameters -> {
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID);
}
});
val accessTokenResponseClient = RestClientRefreshTokenTokenResponseClient()
accessTokenResponseClient.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
定製訪問令牌響應
RestClientRefreshTokenTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌響應的響應引數和錯誤處理的鉤子。
定製 RestClient
您可以透過向 setRestClient() 提供預配置的 RestClient 來定製令牌響應。預設的 RestClient 配置如下
RestClient 配置-
Java
-
Kotlin
RestClient restClient = RestClient.builder()
.messageConverters(messageConverters -> {
messageConverters.clear();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter());
})
.defaultStatusHandler(new OAuth2ErrorResponseErrorHandler())
.build();
RestClientRefreshTokenTokenResponseClient accessTokenResponseClient =
new RestClientRefreshTokenTokenResponseClient();
accessTokenResponseClient.setRestClient(restClient);
val restClient = RestClient.builder()
.messageConverters { messageConverters ->
messageConverters.clear()
messageConverters.add(FormHttpMessageConverter())
messageConverters.add(OAuth2AccessTokenResponseHttpMessageConverter())
}
.defaultStatusHandler(OAuth2ErrorResponseErrorHandler())
.build()
val accessTokenResponseClient = RestClientRefreshTokenTokenResponseClient()
accessTokenResponseClient.setRestClient(restClient)
OAuth2AccessTokenResponseHttpMessageConverter 是 OAuth 2.0 訪問令牌響應的 HttpMessageConverter。您可以透過呼叫 setAccessTokenResponseConverter() 定製令牌響應引數到 OAuth2AccessTokenResponse 的轉換。預設實現是 DefaultMapOAuth2AccessTokenResponseConverter。
OAuth2ErrorResponseErrorHandler 是一個 ResponseErrorHandler,可以處理 OAuth 2.0 錯誤,例如 400 Bad Request。它使用 OAuth2ErrorHttpMessageConverter 將 OAuth 2.0 錯誤引數轉換為 OAuth2Error。您可以透過呼叫 setErrorConverter() 定製令牌響應引數到 OAuth2Error 的轉換。
|
Spring MVC |
定製響應引數
以下示例提供了定製令牌響應引數到 OAuth2AccessTokenResponse 轉換的起點
-
Java
-
Kotlin
OAuth2AccessTokenResponseHttpMessageConverter accessTokenResponseMessageConverter =
new OAuth2AccessTokenResponseHttpMessageConverter();
accessTokenResponseMessageConverter.setAccessTokenResponseConverter(parameters -> {
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build();
});
val accessTokenResponseMessageConverter = OAuth2AccessTokenResponseHttpMessageConverter()
accessTokenResponseMessageConverter.setAccessTokenResponseConverter { parameters ->
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build()
}
定製錯誤處理
以下示例提供了定製錯誤引數到 OAuth2Error 轉換的起點
-
Java
-
Kotlin
OAuth2ErrorHttpMessageConverter errorConverter =
new OAuth2ErrorHttpMessageConverter();
errorConverter.setErrorConverter(parameters -> {
// ...
return new OAuth2Error("custom-error", "custom description", "custom-uri");
});
OAuth2ErrorResponseErrorHandler errorHandler =
new OAuth2ErrorResponseErrorHandler();
errorHandler.setErrorConverter(errorConverter);
val errorConverter = OAuth2ErrorHttpMessageConverter()
errorConverter.setErrorConverter { parameters ->
// ...
return OAuth2Error("custom-error", "custom description", "custom-uri")
}
val errorHandler = OAuth2ErrorResponseErrorHandler()
errorHandler.setErrorConverter(errorConverter)
使用 Builder 定製
無論您是定製 RestClientRefreshTokenTokenResponseClient 還是提供自己的 OAuth2AccessTokenResponseClient 實現,您都可以使用 OAuth2AuthorizedClientProviderBuilder 進行配置(作為釋出 bean 的替代方案),如下所示
-
Java
-
Kotlin
// Customize
OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenTokenResponseClient = ...
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken((configurer) -> configurer.accessTokenResponseClient(refreshTokenTokenResponseClient))
.build();
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Customize
val refreshTokenTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> = ...
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken { it.accessTokenResponseClient(refreshTokenTokenResponseClient) }
.build()
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
|
|
OAuth2RefreshToken 可以選擇在 authorization_code 許可型別的訪問令牌響應中返回。如果 OAuth2AuthorizedClient.getRefreshToken() 可用且 OAuth2AuthorizedClient.getAccessToken() 已過期,它會自動由 RefreshTokenOAuth2AuthorizedClientProvider 重新整理。
客戶端憑據
|
有關客戶端憑據許可的更多詳細資訊,請參閱 OAuth 2.0 授權框架。 |
請求訪問令牌
|
有關客戶端憑據許可的訪問令牌請求/響應協議流,請參閱。 |
客戶端憑據許可的 OAuth2AccessTokenResponseClient 的預設實現是 RestClientClientCredentialsTokenResponseClient,它使用 RestClient 例項在授權伺服器的令牌端點獲取訪問令牌。
RestClientClientCredentialsTokenResponseClient 非常靈活,並提供了多種選項來定製客戶端憑據許可的 OAuth 2.0 訪問令牌請求和響應。從以下用例中選擇以瞭解更多資訊
-
我希望定製訪問令牌請求的標頭
-
我希望定製訪問令牌請求的引數
-
我希望定製訪問令牌響應的引數
定製訪問令牌請求
RestClientClientCredentialsTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌請求的 HTTP 標頭和請求引數的鉤子。
定製請求標頭
有兩種定製 HTTP 標頭的選項
-
透過呼叫
addHeadersConverter()新增額外的標頭 -
透過呼叫
setHeadersConverter()完全定製標頭
您可以使用 addHeadersConverter() 包含額外的標頭,而不會影響新增到每個請求的預設標頭。以下示例在 registrationId 為 spring 時向請求新增 User-Agent 標頭
-
Java
-
Kotlin
RestClientClientCredentialsTokenResponseClient accessTokenResponseClient =
new RestClientClientCredentialsTokenResponseClient();
accessTokenResponseClient.addHeadersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
HttpHeaders headers = new HttpHeaders();
if (clientRegistration.getRegistrationId().equals("spring")) {
headers.set(HttpHeaders.USER_AGENT, "my-user-agent");
}
return headers;
});
val accessTokenResponseClient = RestClientClientCredentialsTokenResponseClient()
accessTokenResponseClient.addHeadersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val headers = HttpHeaders()
if (clientRegistration.getRegistrationId() == "spring") {
headers[HttpHeaders.USER_AGENT] = "my-user-agent"
}
headers
}
您可以透過重新使用 DefaultOAuth2TokenRequestHeadersConverter 或使用 setHeadersConverter() 提供自定義實現來完全定製標頭。以下示例重新使用 DefaultOAuth2TokenRequestHeadersConverter 並停用 encodeClientCredentials,以便 HTTP Basic 憑據不再使用 application/x-www-form-urlencoded 進行編碼
-
Java
-
Kotlin
DefaultOAuth2TokenRequestHeadersConverter headersConverter =
new DefaultOAuth2TokenRequestHeadersConverter();
headersConverter.setEncodeClientCredentials(false);
RestClientClientCredentialsTokenResponseClient accessTokenResponseClient =
new RestClientClientCredentialsTokenResponseClient();
accessTokenResponseClient.setHeadersConverter(headersConverter);
val headersConverter = DefaultOAuth2TokenRequestHeadersConverter()
headersConverter.setEncodeClientCredentials(false)
val accessTokenResponseClient = RestClientClientCredentialsTokenResponseClient()
accessTokenResponseClient.setHeadersConverter(headersConverter)
定製請求引數
有三種定製請求引數的選項
-
透過呼叫
addParametersConverter()新增額外引數 -
透過呼叫
setParametersConverter()覆蓋引數 -
透過呼叫
setParametersCustomizer()完全定製引數
|
使用 |
您可以使用 addParametersConverter() 包含額外的引數,而不會影響新增到每個請求的預設引數。以下示例在 registrationId 為 keycloak 時向請求新增 audience 引數
-
Java
-
Kotlin
RestClientClientCredentialsTokenResponseClient accessTokenResponseClient =
new RestClientClientCredentialsTokenResponseClient();
accessTokenResponseClient.addParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
if (clientRegistration.getRegistrationId().equals("keycloak")) {
parameters.set(OAuth2ParameterNames.AUDIENCE, "my-audience");
}
return parameters;
});
val accessTokenResponseClient = RestClientClientCredentialsTokenResponseClient()
accessTokenResponseClient.addParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "keycloak") {
parameters[OAuth2ParameterNames.AUDIENCE] = "my-audience"
}
parameters
}
您可以使用 setParametersConverter() 覆蓋預設引數。以下示例在 registrationId 為 okta 時覆蓋 client_id 引數
-
Java
-
Kotlin
RestClientClientCredentialsTokenResponseClient accessTokenResponseClient =
new RestClientClientCredentialsTokenResponseClient();
accessTokenResponseClient.setParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
LinkedMultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
if (clientRegistration.getRegistrationId().equals("okta")) {
parameters.set(OAuth2ParameterNames.CLIENT_ID, "my-client");
}
return parameters;
});
val parametersConverter = DefaultOAuth2TokenRequestParametersConverter<OAuth2ClientCredentialsGrantRequest>()
parametersConverter.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
val accessTokenResponseClient = RestClientClientCredentialsTokenResponseClient()
accessTokenResponseClient.setParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "okta") {
parameters[OAuth2ParameterNames.CLIENT_ID] = "my-client"
}
parameters
}
您可以使用 setParametersCustomizer() 完全定製引數(包括省略預設引數)。以下示例在請求中存在 client_assertion 引數時省略 client_id 引數
-
Java
-
Kotlin
RestClientClientCredentialsTokenResponseClient accessTokenResponseClient =
new RestClientClientCredentialsTokenResponseClient();
accessTokenResponseClient.setParametersCustomizer(parameters -> {
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID);
}
});
val accessTokenResponseClient = RestClientClientCredentialsTokenResponseClient()
accessTokenResponseClient.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
定製訪問令牌響應
RestClientClientCredentialsTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌響應的響應引數和錯誤處理的鉤子。
定製 RestClient
您可以透過向 setRestClient() 提供預配置的 RestClient 來定製令牌響應。預設的 RestClient 配置如下
RestClient 配置-
Java
-
Kotlin
RestClient restClient = RestClient.builder()
.messageConverters(messageConverters -> {
messageConverters.clear();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter());
})
.defaultStatusHandler(new OAuth2ErrorResponseErrorHandler())
.build();
RestClientClientCredentialsTokenResponseClient accessTokenResponseClient =
new RestClientClientCredentialsTokenResponseClient();
accessTokenResponseClient.setRestClient(restClient);
val restClient = RestClient.builder()
.messageConverters { messageConverters ->
messageConverters.clear()
messageConverters.add(FormHttpMessageConverter())
messageConverters.add(OAuth2AccessTokenResponseHttpMessageConverter())
}
.defaultStatusHandler(OAuth2ErrorResponseErrorHandler())
.build()
val accessTokenResponseClient = RestClientClientCredentialsTokenResponseClient()
accessTokenResponseClient.setRestClient(restClient)
OAuth2AccessTokenResponseHttpMessageConverter 是 OAuth 2.0 訪問令牌響應的 HttpMessageConverter。您可以透過呼叫 setAccessTokenResponseConverter() 定製令牌響應引數到 OAuth2AccessTokenResponse 的轉換。預設實現是 DefaultMapOAuth2AccessTokenResponseConverter。
OAuth2ErrorResponseErrorHandler 是一個 ResponseErrorHandler,可以處理 OAuth 2.0 錯誤,例如 400 Bad Request。它使用 OAuth2ErrorHttpMessageConverter 將 OAuth 2.0 錯誤引數轉換為 OAuth2Error。您可以透過呼叫 setErrorConverter() 定製令牌響應引數到 OAuth2Error 的轉換。
|
Spring MVC |
定製響應引數
以下示例提供了定製令牌響應引數到 OAuth2AccessTokenResponse 轉換的起點
-
Java
-
Kotlin
OAuth2AccessTokenResponseHttpMessageConverter accessTokenResponseMessageConverter =
new OAuth2AccessTokenResponseHttpMessageConverter();
accessTokenResponseMessageConverter.setAccessTokenResponseConverter(parameters -> {
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build();
});
val accessTokenResponseMessageConverter = OAuth2AccessTokenResponseHttpMessageConverter()
accessTokenResponseMessageConverter.setAccessTokenResponseConverter { parameters ->
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build()
}
定製錯誤處理
以下示例提供了定製錯誤引數到 OAuth2Error 轉換的起點
-
Java
-
Kotlin
OAuth2ErrorHttpMessageConverter errorConverter =
new OAuth2ErrorHttpMessageConverter();
errorConverter.setErrorConverter(parameters -> {
// ...
return new OAuth2Error("custom-error", "custom description", "custom-uri");
});
OAuth2ErrorResponseErrorHandler errorHandler =
new OAuth2ErrorResponseErrorHandler();
errorHandler.setErrorConverter(errorConverter);
val errorConverter = OAuth2ErrorHttpMessageConverter()
errorConverter.setErrorConverter { parameters ->
// ...
return OAuth2Error("custom-error", "custom description", "custom-uri")
}
val errorHandler = OAuth2ErrorResponseErrorHandler()
errorHandler.setErrorConverter(errorConverter)
使用 Builder 定製
無論您是定製 RestClientClientCredentialsTokenResponseClient 還是提供自己的 OAuth2AccessTokenResponseClient 實現,您都可以使用 OAuth2AuthorizedClientProviderBuilder 進行配置(作為釋出 bean 的替代方案),如下所示
-
Java
-
Kotlin
// Customize
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsTokenResponseClient = ...
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials((configurer) -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient))
.build();
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Customize
val clientCredentialsTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> = ...
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials { it.accessTokenResponseClient(clientCredentialsTokenResponseClient) }
.build()
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
|
|
使用訪問令牌
考慮以下 OAuth 2.0 客戶端註冊的 Spring Boot 屬性
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
authorization-grant-type: client_credentials
scope: read, write
provider:
okta:
token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
進一步考慮以下 OAuth2AuthorizedClientManager @Bean
-
Java
-
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.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()
.clientCredentials()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}
給定前面的屬性和 bean,您可以按如下方式獲取 OAuth2AccessToken
-
Java
-
Kotlin
@Controller
public class OAuth2ClientController {
@Autowired
private OAuth2AuthorizedClientManager authorizedClientManager;
@GetMapping("/")
public String index(Authentication authentication,
HttpServletRequest servletRequest,
HttpServletResponse servletResponse) {
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(authentication)
.attributes(attrs -> {
attrs.put(HttpServletRequest.class.getName(), servletRequest);
attrs.put(HttpServletResponse.class.getName(), servletResponse);
})
.build();
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
// ...
return "index";
}
}
class OAuth2ClientController {
@Autowired
private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
@GetMapping("/")
fun index(authentication: Authentication?,
servletRequest: HttpServletRequest,
servletResponse: HttpServletResponse): String {
val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(authentication)
.attributes(Consumer { attrs: MutableMap<String, Any> ->
attrs[HttpServletRequest::class.java.name] = servletRequest
attrs[HttpServletResponse::class.java.name] = servletResponse
})
.build()
val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
val accessToken: OAuth2AccessToken = authorizedClient.accessToken
// ...
return "index"
}
}
|
|
JWT 持有者
|
有關JWT 持有者許可的更多詳細資訊,請參閱 OAuth 2.0 客戶端認證和授權許可的 JSON Web Token (JWT) 配置檔案。 |
請求訪問令牌
|
有關 JWT 持有者許可的訪問令牌請求/響應協議流,請參閱。 |
JWT 持有者許可的 OAuth2AccessTokenResponseClient 的預設實現是 RestClientJwtBearerTokenResponseClient,它使用 RestClient 例項在授權伺服器的令牌端點獲取訪問令牌。
RestClientJwtBearerTokenResponseClient 非常靈活,並提供了多種選項來定製 JWT 持有者許可的 OAuth 2.0 訪問令牌請求和響應。從以下用例中選擇以瞭解更多資訊
-
我希望定製訪問令牌請求的標頭
-
我希望定製訪問令牌請求的引數
-
我希望定製訪問令牌響應的引數
定製訪問令牌請求
RestClientJwtBearerTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌請求的 HTTP 標頭和請求引數的鉤子。
定製請求標頭
有兩種定製 HTTP 標頭的選項
-
透過呼叫
addHeadersConverter()新增額外的標頭 -
透過呼叫
setHeadersConverter()完全定製標頭
您可以使用 addHeadersConverter() 包含額外的標頭,而不會影響新增到每個請求的預設標頭。以下示例在 registrationId 為 spring 時向請求新增 User-Agent 標頭
-
Java
-
Kotlin
RestClientJwtBearerTokenResponseClient accessTokenResponseClient =
new RestClientJwtBearerTokenResponseClient();
accessTokenResponseClient.addHeadersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
HttpHeaders headers = new HttpHeaders();
if (clientRegistration.getRegistrationId().equals("spring")) {
headers.set(HttpHeaders.USER_AGENT, "my-user-agent");
}
return headers;
});
val accessTokenResponseClient = RestClientJwtBearerTokenResponseClient()
accessTokenResponseClient.addHeadersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val headers = HttpHeaders()
if (clientRegistration.getRegistrationId() == "spring") {
headers[HttpHeaders.USER_AGENT] = "my-user-agent"
}
headers
}
您可以透過重新使用 DefaultOAuth2TokenRequestHeadersConverter 或使用 setHeadersConverter() 提供自定義實現來完全定製標頭。以下示例重新使用 DefaultOAuth2TokenRequestHeadersConverter 並停用 encodeClientCredentials,以便 HTTP Basic 憑據不再使用 application/x-www-form-urlencoded 進行編碼
-
Java
-
Kotlin
DefaultOAuth2TokenRequestHeadersConverter headersConverter =
new DefaultOAuth2TokenRequestHeadersConverter();
headersConverter.setEncodeClientCredentials(false);
RestClientJwtBearerTokenResponseClient accessTokenResponseClient =
new RestClientJwtBearerTokenResponseClient();
accessTokenResponseClient.setHeadersConverter(headersConverter);
val headersConverter = DefaultOAuth2TokenRequestHeadersConverter()
headersConverter.setEncodeClientCredentials(false)
val accessTokenResponseClient = RestClientJwtBearerTokenResponseClient()
accessTokenResponseClient.setHeadersConverter(headersConverter)
定製請求引數
有三種定製請求引數的選項
-
透過呼叫
addParametersConverter()新增額外引數 -
透過呼叫
setParametersConverter()覆蓋引數 -
透過呼叫
setParametersCustomizer()完全定製引數
|
使用 |
您可以使用 addParametersConverter() 包含額外的引數,而不會影響新增到每個請求的預設引數。以下示例在 registrationId 為 keycloak 時向請求新增 audience 引數
-
Java
-
Kotlin
RestClientJwtBearerTokenResponseClient accessTokenResponseClient =
new RestClientJwtBearerTokenResponseClient();
accessTokenResponseClient.addParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
if (clientRegistration.getRegistrationId().equals("keycloak")) {
parameters.set(OAuth2ParameterNames.AUDIENCE, "my-audience");
}
return parameters;
});
val accessTokenResponseClient = RestClientJwtBearerTokenResponseClient()
accessTokenResponseClient.addParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "keycloak") {
parameters[OAuth2ParameterNames.AUDIENCE] = "my-audience"
}
parameters
}
您可以使用 setParametersConverter() 覆蓋預設引數。以下示例在 registrationId 為 okta 時覆蓋 client_id 引數
-
Java
-
Kotlin
RestClientJwtBearerTokenResponseClient accessTokenResponseClient =
new RestClientJwtBearerTokenResponseClient();
accessTokenResponseClient.setParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
LinkedMultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
if (clientRegistration.getRegistrationId().equals("okta")) {
parameters.set(OAuth2ParameterNames.CLIENT_ID, "my-client");
}
return parameters;
});
val parametersConverter = DefaultOAuth2TokenRequestParametersConverter<JwtBearerGrantRequest>()
parametersConverter.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
val accessTokenResponseClient = RestClientJwtBearerTokenResponseClient()
accessTokenResponseClient.setParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "okta") {
parameters[OAuth2ParameterNames.CLIENT_ID] = "my-client"
}
parameters
}
您可以使用 setParametersCustomizer() 完全定製引數(包括省略預設引數)。以下示例在請求中存在 client_assertion 引數時省略 client_id 引數
-
Java
-
Kotlin
RestClientJwtBearerTokenResponseClient accessTokenResponseClient =
new RestClientJwtBearerTokenResponseClient();
accessTokenResponseClient.setParametersCustomizer(parameters -> {
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID);
}
});
val accessTokenResponseClient = RestClientJwtBearerTokenResponseClient()
accessTokenResponseClient.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
定製訪問令牌響應
RestClientJwtBearerTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌響應的響應引數和錯誤處理的鉤子。
定製 RestClient
您可以透過向 setRestClient() 提供預配置的 RestClient 來定製令牌響應。預設的 RestClient 配置如下
RestClient 配置-
Java
-
Kotlin
RestClient restClient = RestClient.builder()
.messageConverters(messageConverters -> {
messageConverters.clear();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter());
})
.defaultStatusHandler(new OAuth2ErrorResponseErrorHandler())
.build();
RestClientJwtBearerTokenResponseClient accessTokenResponseClient =
new RestClientJwtBearerTokenResponseClient();
accessTokenResponseClient.setRestClient(restClient);
val restClient = RestClient.builder()
.messageConverters { messageConverters ->
messageConverters.clear()
messageConverters.add(FormHttpMessageConverter())
messageConverters.add(OAuth2AccessTokenResponseHttpMessageConverter())
}
.defaultStatusHandler(OAuth2ErrorResponseErrorHandler())
.build()
val accessTokenResponseClient = RestClientJwtBearerTokenResponseClient()
accessTokenResponseClient.setRestClient(restClient)
OAuth2AccessTokenResponseHttpMessageConverter 是 OAuth 2.0 訪問令牌響應的 HttpMessageConverter。您可以透過呼叫 setAccessTokenResponseConverter() 定製令牌響應引數到 OAuth2AccessTokenResponse 的轉換。預設實現是 DefaultMapOAuth2AccessTokenResponseConverter。
OAuth2ErrorResponseErrorHandler 是一個 ResponseErrorHandler,可以處理 OAuth 2.0 錯誤,例如 400 Bad Request。它使用 OAuth2ErrorHttpMessageConverter 將 OAuth 2.0 錯誤引數轉換為 OAuth2Error。您可以透過呼叫 setErrorConverter() 定製令牌響應引數到 OAuth2Error 的轉換。
|
Spring MVC |
定製響應引數
以下示例提供了定製令牌響應引數到 OAuth2AccessTokenResponse 轉換的起點
-
Java
-
Kotlin
OAuth2AccessTokenResponseHttpMessageConverter accessTokenResponseMessageConverter =
new OAuth2AccessTokenResponseHttpMessageConverter();
accessTokenResponseMessageConverter.setAccessTokenResponseConverter(parameters -> {
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build();
});
val accessTokenResponseMessageConverter = OAuth2AccessTokenResponseHttpMessageConverter()
accessTokenResponseMessageConverter.setAccessTokenResponseConverter { parameters ->
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build()
}
定製錯誤處理
以下示例提供了定製錯誤引數到 OAuth2Error 轉換的起點
-
Java
-
Kotlin
OAuth2ErrorHttpMessageConverter errorConverter =
new OAuth2ErrorHttpMessageConverter();
errorConverter.setErrorConverter(parameters -> {
// ...
return new OAuth2Error("custom-error", "custom description", "custom-uri");
});
OAuth2ErrorResponseErrorHandler errorHandler =
new OAuth2ErrorResponseErrorHandler();
errorHandler.setErrorConverter(errorConverter);
val errorConverter = OAuth2ErrorHttpMessageConverter()
errorConverter.setErrorConverter { parameters ->
// ...
return OAuth2Error("custom-error", "custom description", "custom-uri")
}
val errorHandler = OAuth2ErrorResponseErrorHandler()
errorHandler.setErrorConverter(errorConverter)
使用 Builder 定製
無論您是定製 RestClientJwtBearerTokenResponseClient 還是提供自己的 OAuth2AccessTokenResponseClient 實現,您都可以使用 OAuth2AuthorizedClientProviderBuilder 進行配置(作為釋出 bean 的替代方案),如下所示
-
Java
-
Kotlin
// Customize
OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerTokenResponseClient = ...
JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider = new JwtBearerOAuth2AuthorizedClientProvider();
jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient);
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.provider(jwtBearerAuthorizedClientProvider)
.build();
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Customize
val jwtBearerTokenResponseClient: OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> = ...
val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient)
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.provider(jwtBearerAuthorizedClientProvider)
.build()
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
使用訪問令牌
給定以下 OAuth 2.0 客戶端註冊的 Spring Boot 屬性
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
authorization-grant-type: urn:ietf:params:oauth:grant-type:jwt-bearer
scope: read
provider:
okta:
token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
……以及 OAuth2AuthorizedClientManager @Bean
-
Java
-
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider =
new JwtBearerOAuth2AuthorizedClientProvider();
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.provider(jwtBearerAuthorizedClientProvider)
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.provider(jwtBearerAuthorizedClientProvider)
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}
您可以按如下方式獲取 OAuth2AccessToken
-
Java
-
Kotlin
@RestController
public class OAuth2ResourceServerController {
@Autowired
private OAuth2AuthorizedClientManager authorizedClientManager;
@GetMapping("/resource")
public String resource(JwtAuthenticationToken jwtAuthentication) {
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(jwtAuthentication)
.build();
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
// ...
}
}
class OAuth2ResourceServerController {
@Autowired
private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
@GetMapping("/resource")
fun resource(jwtAuthentication: JwtAuthenticationToken?): String {
val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(jwtAuthentication)
.build()
val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
val accessToken: OAuth2AccessToken = authorizedClient.accessToken
// ...
}
}
|
|
|
如果您需要從不同的源解析 |
令牌交換
|
有關令牌交換許可的更多詳細資訊,請參閱 OAuth 2.0 令牌交換。 |
請求訪問令牌
|
有關令牌交換許可的令牌交換請求和響應協議流,請參閱。 |
令牌交換許可的 OAuth2AccessTokenResponseClient 的預設實現是 RestClientTokenExchangeTokenResponseClient,它使用 RestClient 例項在授權伺服器的令牌端點獲取訪問令牌。
RestClientTokenExchangeTokenResponseClient 非常靈活,並提供了多種選項來定製令牌交換許可的 OAuth 2.0 訪問令牌請求和響應。從以下用例中選擇以瞭解更多資訊
-
我希望定製訪問令牌請求的標頭
-
我希望定製訪問令牌請求的引數
-
我希望定製訪問令牌響應的引數
定製訪問令牌請求
RestClientTokenExchangeTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌請求的 HTTP 標頭和請求引數的鉤子。
定製請求標頭
有兩種定製 HTTP 標頭的選項
-
透過呼叫
addHeadersConverter()新增額外的標頭 -
透過呼叫
setHeadersConverter()完全定製標頭
您可以使用 addHeadersConverter() 包含額外的標頭,而不會影響新增到每個請求的預設標頭。以下示例在 registrationId 為 spring 時向請求新增 User-Agent 標頭
-
Java
-
Kotlin
RestClientTokenExchangeTokenResponseClient accessTokenResponseClient =
new RestClientTokenExchangeTokenResponseClient();
accessTokenResponseClient.addHeadersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
HttpHeaders headers = new HttpHeaders();
if (clientRegistration.getRegistrationId().equals("spring")) {
headers.set(HttpHeaders.USER_AGENT, "my-user-agent");
}
return headers;
});
val accessTokenResponseClient = RestClientTokenExchangeTokenResponseClient()
accessTokenResponseClient.addHeadersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val headers = HttpHeaders()
if (clientRegistration.getRegistrationId() == "spring") {
headers[HttpHeaders.USER_AGENT] = "my-user-agent"
}
headers
}
您可以透過重新使用 DefaultOAuth2TokenRequestHeadersConverter 或使用 setHeadersConverter() 提供自定義實現來完全定製標頭。以下示例重新使用 DefaultOAuth2TokenRequestHeadersConverter 並停用 encodeClientCredentials,以便 HTTP Basic 憑據不再使用 application/x-www-form-urlencoded 進行編碼
-
Java
-
Kotlin
DefaultOAuth2TokenRequestHeadersConverter headersConverter =
new DefaultOAuth2TokenRequestHeadersConverter();
headersConverter.setEncodeClientCredentials(false);
RestClientTokenExchangeTokenResponseClient accessTokenResponseClient =
new RestClientTokenExchangeTokenResponseClient();
accessTokenResponseClient.setHeadersConverter(headersConverter);
val headersConverter = DefaultOAuth2TokenRequestHeadersConverter()
headersConverter.setEncodeClientCredentials(false)
val accessTokenResponseClient = RestClientTokenExchangeTokenResponseClient()
accessTokenResponseClient.setHeadersConverter(headersConverter)
定製請求引數
有三種定製請求引數的選項
-
透過呼叫
addParametersConverter()新增額外引數 -
透過呼叫
setParametersConverter()覆蓋引數 -
透過呼叫
setParametersCustomizer()完全定製引數
|
使用 |
您可以使用 addParametersConverter() 包含額外的引數,而不會影響新增到每個請求的預設引數。以下示例在 registrationId 為 keycloak 時向請求新增 audience 引數
-
Java
-
Kotlin
RestClientTokenExchangeTokenResponseClient accessTokenResponseClient =
new RestClientTokenExchangeTokenResponseClient();
accessTokenResponseClient.addParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
if (clientRegistration.getRegistrationId().equals("keycloak")) {
parameters.set(OAuth2ParameterNames.AUDIENCE, "my-audience");
}
return parameters;
});
val accessTokenResponseClient = RestClientTokenExchangeTokenResponseClient()
accessTokenResponseClient.addParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "keycloak") {
parameters[OAuth2ParameterNames.AUDIENCE] = "my-audience"
}
parameters
}
您可以使用 setParametersConverter() 覆蓋預設引數。以下示例在 registrationId 為 okta 時覆蓋 client_id 引數
-
Java
-
Kotlin
RestClientTokenExchangeTokenResponseClient accessTokenResponseClient =
new RestClientTokenExchangeTokenResponseClient();
accessTokenResponseClient.setParametersConverter(grantRequest -> {
ClientRegistration clientRegistration = grantRequest.getClientRegistration();
LinkedMultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
if (clientRegistration.getRegistrationId().equals("okta")) {
parameters.set(OAuth2ParameterNames.CLIENT_ID, "my-client");
}
return parameters;
});
val parametersConverter = DefaultOAuth2TokenRequestParametersConverter<TokenExchangeGrantRequest>()
parametersConverter.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
val accessTokenResponseClient = RestClientTokenExchangeTokenResponseClient()
accessTokenResponseClient.setParametersConverter { grantRequest ->
val clientRegistration = grantRequest.getClientRegistration()
val parameters = LinkedMultiValueMap<String, String>()
if (clientRegistration.getRegistrationId() == "okta") {
parameters[OAuth2ParameterNames.CLIENT_ID] = "my-client"
}
parameters
}
您可以使用 setParametersCustomizer() 完全定製引數(包括省略預設引數)。以下示例在請求中存在 client_assertion 引數時省略 client_id 引數
-
Java
-
Kotlin
RestClientTokenExchangeTokenResponseClient accessTokenResponseClient =
new RestClientTokenExchangeTokenResponseClient();
accessTokenResponseClient.setParametersCustomizer(parameters -> {
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID);
}
});
val accessTokenResponseClient = RestClientTokenExchangeTokenResponseClient()
accessTokenResponseClient.setParametersCustomizer { parameters ->
if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
parameters.remove(OAuth2ParameterNames.CLIENT_ID)
}
}
定製訪問令牌響應
RestClientTokenExchangeTokenResponseClient 提供了用於定製 OAuth 2.0 訪問令牌響應的響應引數和錯誤處理的鉤子。
定製 RestClient
您可以透過向 setRestClient() 提供預配置的 RestClient 來定製令牌響應。預設的 RestClient 配置如下
RestClient 配置-
Java
-
Kotlin
RestClient restClient = RestClient.builder()
.messageConverters(messageConverters -> {
messageConverters.clear();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter());
})
.defaultStatusHandler(new OAuth2ErrorResponseErrorHandler())
.build();
RestClientTokenExchangeTokenResponseClient accessTokenResponseClient =
new RestClientTokenExchangeTokenResponseClient();
accessTokenResponseClient.setRestClient(restClient);
val restClient = RestClient.builder()
.messageConverters { messageConverters ->
messageConverters.clear()
messageConverters.add(FormHttpMessageConverter())
messageConverters.add(OAuth2AccessTokenResponseHttpMessageConverter())
}
.defaultStatusHandler(OAuth2ErrorResponseErrorHandler())
.build()
val accessTokenResponseClient = RestClientTokenExchangeTokenResponseClient()
accessTokenResponseClient.setRestClient(restClient)
OAuth2AccessTokenResponseHttpMessageConverter 是 OAuth 2.0 訪問令牌響應的 HttpMessageConverter。您可以透過呼叫 setAccessTokenResponseConverter() 定製令牌響應引數到 OAuth2AccessTokenResponse 的轉換。預設實現是 DefaultMapOAuth2AccessTokenResponseConverter。
OAuth2ErrorResponseErrorHandler 是一個 ResponseErrorHandler,可以處理 OAuth 2.0 錯誤,例如 400 Bad Request。它使用 OAuth2ErrorHttpMessageConverter 將 OAuth 2.0 錯誤引數轉換為 OAuth2Error。您可以透過呼叫 setErrorConverter() 定製令牌響應引數到 OAuth2Error 的轉換。
|
Spring MVC |
定製響應引數
以下示例提供了定製令牌響應引數到 OAuth2AccessTokenResponse 轉換的起點
-
Java
-
Kotlin
OAuth2AccessTokenResponseHttpMessageConverter accessTokenResponseMessageConverter =
new OAuth2AccessTokenResponseHttpMessageConverter();
accessTokenResponseMessageConverter.setAccessTokenResponseConverter(parameters -> {
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build();
});
val accessTokenResponseMessageConverter = OAuth2AccessTokenResponseHttpMessageConverter()
accessTokenResponseMessageConverter.setAccessTokenResponseConverter { parameters ->
// ...
return OAuth2AccessTokenResponse.withToken("custom-token")
// ...
.build()
}
定製錯誤處理
以下示例提供了定製錯誤引數到 OAuth2Error 轉換的起點
-
Java
-
Kotlin
OAuth2ErrorHttpMessageConverter errorConverter =
new OAuth2ErrorHttpMessageConverter();
errorConverter.setErrorConverter(parameters -> {
// ...
return new OAuth2Error("custom-error", "custom description", "custom-uri");
});
OAuth2ErrorResponseErrorHandler errorHandler =
new OAuth2ErrorResponseErrorHandler();
errorHandler.setErrorConverter(errorConverter);
val errorConverter = OAuth2ErrorHttpMessageConverter()
errorConverter.setErrorConverter { parameters ->
// ...
return OAuth2Error("custom-error", "custom description", "custom-uri")
}
val errorHandler = OAuth2ErrorResponseErrorHandler()
errorHandler.setErrorConverter(errorConverter)
使用 Builder 定製
無論您是定製 RestClientTokenExchangeTokenResponseClient 還是提供自己的 OAuth2AccessTokenResponseClient 實現,您都可以使用 OAuth2AuthorizedClientProviderBuilder 進行配置(作為釋出 bean 的替代方案),如下所示
-
Java
-
Kotlin
// Customize
OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeTokenResponseClient = ...
TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider = new TokenExchangeOAuth2AuthorizedClientProvider();
tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeTokenResponseClient);
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.provider(tokenExchangeAuthorizedClientProvider)
.build();
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Customize
val tokenExchangeTokenResponseClient: OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> = ...
val tokenExchangeAuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeTokenResponseClient)
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.provider(tokenExchangeAuthorizedClientProvider)
.build()
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
使用訪問令牌
給定以下 OAuth 2.0 客戶端註冊的 Spring Boot 屬性
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
authorization-grant-type: urn:ietf:params:oauth:grant-type:token-exchange
scope: read
provider:
okta:
token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
……以及 OAuth2AuthorizedClientManager @Bean
-
Java
-
Kotlin
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider =
new TokenExchangeOAuth2AuthorizedClientProvider();
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.provider(tokenExchangeAuthorizedClientProvider)
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val tokenExchangeAuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.provider(tokenExchangeAuthorizedClientProvider)
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
return authorizedClientManager
}
您可以按如下方式獲取 OAuth2AccessToken
-
Java
-
Kotlin
@RestController
public class OAuth2ResourceServerController {
@Autowired
private OAuth2AuthorizedClientManager authorizedClientManager;
@GetMapping("/resource")
public String resource(JwtAuthenticationToken jwtAuthentication) {
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(jwtAuthentication)
.build();
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
// ...
}
}
class OAuth2ResourceServerController {
@Autowired
private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
@GetMapping("/resource")
fun resource(jwtAuthentication: JwtAuthenticationToken?): String {
val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(jwtAuthentication)
.build()
val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
val accessToken: OAuth2AccessToken = authorizedClient.accessToken
// ...
}
}
|
|
|
如果您需要從不同的源解析主題令牌,您可以向 |
|
如果您需要解析參與者令牌,您可以向 |