進階組態

HttpSecurity.oauth2Login() 為自訂 OAuth 2.0 登入提供了許多組態選項。主要的組態選項依其協定端點對應項分組。

例如,oauth2Login().authorizationEndpoint() 允許組態授權端點,而 oauth2Login().tokenEndpoint() 允許組態權杖端點

以下程式碼顯示範例

進階 OAuth2 登入組態
  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .authorizationEndpoint(authorization -> authorization
			            ...
			    )
			    .redirectionEndpoint(redirection -> redirection
			            ...
			    )
			    .tokenEndpoint(token -> token
			            ...
			    )
			    .userInfoEndpoint(userInfo -> userInfo
			            ...
			    )
			);
		return http.build();
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                authorizationEndpoint {
                    ...
                }
                redirectionEndpoint {
                    ...
                }
                tokenEndpoint {
                    ...
                }
                userInfoEndpoint {
                    ...
                }
            }
        }
        return http.build()
    }
}

oauth2Login() DSL 的主要目標是與規格中定義的命名緊密對齊。

OAuth 2.0 授權框架將 協定端點 定義如下

授權流程使用兩個授權伺服器端點 (HTTP 資源)

  • 授權端點:用戶端使用此端點透過使用者代理程式重新導向從資源擁有者取得授權。

  • 權杖端點:用戶端使用此端點交換授權許可以取得存取權杖,通常使用用戶端驗證。

授權流程也使用一個用戶端端點

  • 重新導向端點:授權伺服器使用此端點傳回回應,其中包含透過資源擁有者使用者代理程式傳回給用戶端的授權憑證。

OpenID Connect Core 1.0 規格將 UserInfo 端點 定義如下

UserInfo 端點是 OAuth 2.0 保護資源,可傳回關於已驗證最終使用者的宣告。為了取得關於最終使用者的請求宣告,用戶端透過使用透過 OpenID Connect 驗證取得的存取權杖,向 UserInfo 端點發出請求。這些宣告通常由 JSON 物件表示,其中包含宣告的名稱值組集合。

以下程式碼顯示 oauth2Login() DSL 的完整組態選項

OAuth2 登入組態選項
  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .clientRegistrationRepository(this.clientRegistrationRepository())
			    .authorizedClientRepository(this.authorizedClientRepository())
			    .authorizedClientService(this.authorizedClientService())
			    .loginPage("/login")
			    .authorizationEndpoint(authorization -> authorization
			        .baseUri(this.authorizationRequestBaseUri())
			        .authorizationRequestRepository(this.authorizationRequestRepository())
			        .authorizationRequestResolver(this.authorizationRequestResolver())
			    )
			    .redirectionEndpoint(redirection -> redirection
			        .baseUri(this.authorizationResponseBaseUri())
			    )
			    .tokenEndpoint(token -> token
			        .accessTokenResponseClient(this.accessTokenResponseClient())
			    )
			    .userInfoEndpoint(userInfo -> userInfo
			        .userAuthoritiesMapper(this.userAuthoritiesMapper())
			        .userService(this.oauth2UserService())
			        .oidcUserService(this.oidcUserService())
			    )
			);
		return http.build();
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                clientRegistrationRepository = clientRegistrationRepository()
                authorizedClientRepository = authorizedClientRepository()
                authorizedClientService = authorizedClientService()
                loginPage = "/login"
                authorizationEndpoint {
                    baseUri = authorizationRequestBaseUri()
                    authorizationRequestRepository = authorizationRequestRepository()
                    authorizationRequestResolver = authorizationRequestResolver()
                }
                redirectionEndpoint {
                    baseUri = authorizationResponseBaseUri()
                }
                tokenEndpoint {
                    accessTokenResponseClient = accessTokenResponseClient()
                }
                userInfoEndpoint {
                    userAuthoritiesMapper = userAuthoritiesMapper()
                    userService = oauth2UserService()
                    oidcUserService = oidcUserService()
                }
            }
        }
        return http.build()
    }
}

除了 oauth2Login() DSL 之外,也支援 XML 組態。

以下程式碼顯示 安全性命名空間 中可用的完整組態選項

OAuth2 登入 XML 組態選項
<http>
	<oauth2-login client-registration-repository-ref="clientRegistrationRepository"
				  authorized-client-repository-ref="authorizedClientRepository"
				  authorized-client-service-ref="authorizedClientService"
				  authorization-request-repository-ref="authorizationRequestRepository"
				  authorization-request-resolver-ref="authorizationRequestResolver"
				  access-token-response-client-ref="accessTokenResponseClient"
				  user-authorities-mapper-ref="userAuthoritiesMapper"
				  user-service-ref="oauth2UserService"
				  oidc-user-service-ref="oidcUserService"
				  login-processing-url="/login/oauth2/code/*"
				  login-page="/login"
				  authentication-success-handler-ref="authenticationSuccessHandler"
				  authentication-failure-handler-ref="authenticationFailureHandler"
				  jwt-decoder-factory-ref="jwtDecoderFactory"/>
</http>

以下章節將更詳細地介紹每個可用的組態選項

OAuth 2.0 登入頁面

預設情況下,OAuth 2.0 登入頁面由 DefaultLoginPageGeneratingFilter 自動產生。預設登入頁面會顯示每個已組態的 OAuth 用戶端,並以其 ClientRegistration.clientName 作為連結,此連結能夠啟動授權請求 (或 OAuth 2.0 登入)。

為了讓 DefaultLoginPageGeneratingFilter 顯示已組態 OAuth 用戶端的連結,已註冊的 ClientRegistrationRepository 也需要實作 Iterable<ClientRegistration>。請參閱 InMemoryClientRegistrationRepository 以供參考。

每個 OAuth 用戶端的連結目的地預設為以下

OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/{registrationId}"

以下行顯示範例

<a href="/oauth2/authorization/google">Google</a>

若要覆寫預設登入頁面,請組態 oauth2Login().loginPage() 和 (選擇性) oauth2Login().authorizationEndpoint().baseUri()

以下清單顯示範例

OAuth2 登入頁面組態
  • Java

  • Kotlin

  • Xml

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .loginPage("/login/oauth2")
			    ...
			    .authorizationEndpoint(authorization -> authorization
			        .baseUri("/login/oauth2/authorization")
			        ...
			    )
			);
		return http.build();
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                loginPage = "/login/oauth2"
                authorizationEndpoint {
                    baseUri = "/login/oauth2/authorization"
                }
            }
        }
        return http.build()
    }
}
<http>
	<oauth2-login login-page="/login/oauth2"
				  ...
    />
</http>

您需要提供一個 @Controller 和一個 @RequestMapping("/login/oauth2"),使其能夠呈現自訂登入頁面。

如先前所述,組態 oauth2Login().authorizationEndpoint().baseUri() 是選擇性的。但是,如果您選擇自訂它,請確保每個 OAuth 用戶端的連結都符合 authorizationEndpoint().baseUri()

以下行顯示範例

<a href="/login/oauth2/authorization/google">Google</a>

重新導向端點

重新導向端點由授權伺服器使用,透過資源擁有者使用者代理程式將授權回應 (其中包含授權憑證) 傳回給用戶端。

OAuth 2.0 登入利用授權碼授與。因此,授權憑證是授權碼。

預設授權回應 baseUri (重新導向端點) 為 /login/oauth2/code/*,定義於 OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI 中。

如果您想要自訂授權回應 baseUri,請如下組態

重新導向端點組態
  • Java

  • Kotlin

  • Xml

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

    @Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .redirectionEndpoint(redirection -> redirection
			        .baseUri("/login/oauth2/callback/*")
			        ...
			    )
			);
		return http.build();
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                redirectionEndpoint {
                    baseUri = "/login/oauth2/callback/*"
                }
            }
        }
        return http.build()
    }
}
<http>
	<oauth2-login login-processing-url="/login/oauth2/callback/*"
				  ...
    />
</http>

您也需要確保 ClientRegistration.redirectUri 符合自訂授權回應 baseUri

以下清單顯示範例

  • Java

  • Kotlin

return CommonOAuth2Provider.GOOGLE.getBuilder("google")
	.clientId("google-client-id")
	.clientSecret("google-client-secret")
	.redirectUri("{baseUrl}/login/oauth2/callback/{registrationId}")
	.build();
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
    .clientId("google-client-id")
    .clientSecret("google-client-secret")
    .redirectUri("{baseUrl}/login/oauth2/callback/{registrationId}")
    .build()

UserInfo 端點

UserInfo 端點包含許多組態選項,如下列子章節所述

對應使用者權限

在使用者成功透過 OAuth 2.0 提供者驗證後,OAuth2User.getAuthorities() (或 OidcUser.getAuthorities()) 包含從 OAuth2UserRequest.getAccessToken().getScopes() 填入並以 SCOPE_ 作為前綴的授與權限清單。這些授與權限可以對應到一組新的 GrantedAuthority 實例,這些實例在完成驗證時提供給 OAuth2AuthenticationToken

OAuth2AuthenticationToken.getAuthorities() 用於授權請求,例如 hasRole('USER')hasRole('ADMIN')

在對應使用者權限時,有幾個選項可供選擇

使用 GrantedAuthoritiesMapper

GrantedAuthoritiesMapper 獲取授與權限清單,其中包含 OAuth2UserAuthority 類型的特殊權限和權限字串 OAUTH2_USER (或 OidcUserAuthority 和權限字串 OIDC_USER)。

提供 GrantedAuthoritiesMapper 的實作並組態它,如下所示

授與權限對應器組態
  • Java

  • Kotlin

  • Xml

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

    @Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .userAuthoritiesMapper(this.userAuthoritiesMapper())
			        ...
			    )
			);
		return http.build();
	}

	private GrantedAuthoritiesMapper userAuthoritiesMapper() {
		return (authorities) -> {
			Set<GrantedAuthority> mappedAuthorities = new HashSet<>();

			authorities.forEach(authority -> {
				if (OidcUserAuthority.class.isInstance(authority)) {
					OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority;

					OidcIdToken idToken = oidcUserAuthority.getIdToken();
					OidcUserInfo userInfo = oidcUserAuthority.getUserInfo();

					// Map the claims found in idToken and/or userInfo
					// to one or more GrantedAuthority's and add it to mappedAuthorities

				} else if (OAuth2UserAuthority.class.isInstance(authority)) {
					OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority;

					Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();

					// Map the attributes found in userAttributes
					// to one or more GrantedAuthority's and add it to mappedAuthorities

				}
			});

			return mappedAuthorities;
		};
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    userAuthoritiesMapper = userAuthoritiesMapper()
                }
            }
        }
        return http.build()
    }

    private fun userAuthoritiesMapper(): GrantedAuthoritiesMapper = GrantedAuthoritiesMapper { authorities: Collection<GrantedAuthority> ->
        val mappedAuthorities = emptySet<GrantedAuthority>()

        authorities.forEach { authority ->
            if (authority is OidcUserAuthority) {
                val idToken = authority.idToken
                val userInfo = authority.userInfo
                // Map the claims found in idToken and/or userInfo
                // to one or more GrantedAuthority's and add it to mappedAuthorities
            } else if (authority is OAuth2UserAuthority) {
                val userAttributes = authority.attributes
                // Map the attributes found in userAttributes
                // to one or more GrantedAuthority's and add it to mappedAuthorities
            }
        }

        mappedAuthorities
    }
}
<http>
	<oauth2-login user-authorities-mapper-ref="userAuthoritiesMapper"
				  ...
    />
</http>

或者,您可以註冊 GrantedAuthoritiesMapper @Bean 以使其自動應用於組態,如下所示

授與權限對應器 Bean 組態
  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
		    .oauth2Login(withDefaults());
		return http.build();
	}

	@Bean
	public GrantedAuthoritiesMapper userAuthoritiesMapper() {
		...
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login { }
        }
        return http.build()
    }

    @Bean
    fun userAuthoritiesMapper(): GrantedAuthoritiesMapper {
        ...
    }
}

使用 OAuth2UserService 的委派式策略

與使用 GrantedAuthoritiesMapper 相比,此策略更進階。但是,它也更靈活,因為它可以讓您存取 OAuth2UserRequestOAuth2User (當使用 OAuth 2.0 UserService 時) 或 OidcUserRequestOidcUser (當使用 OpenID Connect 1.0 UserService 時)。

OAuth2UserRequest (和 OidcUserRequest) 讓您可以存取相關聯的 OAuth2AccessToken,這在委派者需要在它可以對應使用者的自訂權限之前,從受保護資源提取權限資訊的情況下非常有用。

以下範例示範如何使用 OpenID Connect 1.0 UserService 實作和組態委派式策略

OAuth2UserService 組態
  • Java

  • Kotlin

  • Xml

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .oidcUserService(this.oidcUserService())
			        ...
			    )
			);
		return http.build();
	}

	private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
		final OidcUserService delegate = new OidcUserService();

		return (userRequest) -> {
			// Delegate to the default implementation for loading a user
			OidcUser oidcUser = delegate.loadUser(userRequest);

			OAuth2AccessToken accessToken = userRequest.getAccessToken();
			Set<GrantedAuthority> mappedAuthorities = new HashSet<>();

			// TODO
			// 1) Fetch the authority information from the protected resource using accessToken
			// 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities

			// 3) Create a copy of oidcUser but use the mappedAuthorities instead
			ProviderDetails providerDetails = userRequest.getClientRegistration().getProviderDetails();
			String userNameAttributeName = providerDetails.getUserInfoEndpoint().getUserNameAttributeName();
			if (StringUtils.hasText(userNameAttributeName)) {
				oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo(), userNameAttributeName);
			} else {
				oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
			}

			return oidcUser;
		};
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig  {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    oidcUserService = oidcUserService()
                }
            }
        }
        return http.build()
    }

    @Bean
    fun oidcUserService(): OAuth2UserService<OidcUserRequest, OidcUser> {
        val delegate = OidcUserService()

        return OAuth2UserService { userRequest ->
            // Delegate to the default implementation for loading a user
            val oidcUser = delegate.loadUser(userRequest)

            val accessToken = userRequest.accessToken
            val mappedAuthorities = HashSet<GrantedAuthority>()

            // TODO
            // 1) Fetch the authority information from the protected resource using accessToken
            // 2) Map the authority information to one or more GrantedAuthority's and add it to mappedAuthorities
            // 3) Create a copy of oidcUser but use the mappedAuthorities instead
            val providerDetails = userRequest.getClientRegistration().getProviderDetails()
            val userNameAttributeName = providerDetails.getUserInfoEndpoint().getUserNameAttributeName()
            if (StringUtils.hasText(userNameAttributeName)) {
                DefaultOidcUser(mappedAuthorities, oidcUser.idToken, oidcUser.userInfo, userNameAttributeName)
            } else {
                DefaultOidcUser(mappedAuthorities, oidcUser.idToken, oidcUser.userInfo)
            }
        }
    }
}
<http>
	<oauth2-login oidc-user-service-ref="oidcUserService"
				  ...
    />
</http>

OAuth 2.0 UserService

DefaultOAuth2UserServiceOAuth2UserService 的實作,支援標準 OAuth 2.0 提供者。

OAuth2UserService 從 UserInfo 端點取得最終使用者 (資源擁有者) 的使用者屬性 (透過使用在授權流程期間授與給用戶端的存取權杖),並以 OAuth2User 的形式傳回 AuthenticatedPrincipal

當在 UserInfo 端點請求使用者屬性時,DefaultOAuth2UserService 使用 RestOperations 實例。

如果您需要自訂 UserInfo 請求的預先處理,您可以提供 DefaultOAuth2UserService.setRequestEntityConverter() 和自訂 Converter<OAuth2UserRequest, RequestEntity<?>>。預設實作 OAuth2UserRequestEntityConverter 建置 UserInfo 請求的 RequestEntity 表示法,預設情況下在 Authorization 標頭中設定 OAuth2AccessToken

另一方面,如果您需要自訂 UserInfo 回應的後續處理,您需要提供 DefaultOAuth2UserService.setRestOperations() 和自訂組態的 RestOperations。預設 RestOperations 組態如下

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());

OAuth2ErrorResponseErrorHandler 是一個 ResponseErrorHandler,可以處理 OAuth 2.0 錯誤 (400 Bad Request)。它使用 OAuth2ErrorHttpMessageConverter 將 OAuth 2.0 錯誤參數轉換為 OAuth2Error

無論您是自訂 DefaultOAuth2UserService 還是提供您自己的 OAuth2UserService 實作,您都需要如下組態它

  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
			    .userInfoEndpoint(userInfo -> userInfo
			        .userService(this.oauth2UserService())
			        ...
			    )
			);
		return http.build();
	}

	private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
		...
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    userService = oauth2UserService()
                    // ...
                }
            }
        }
        return http.build()
    }

    private fun oauth2UserService(): OAuth2UserService<OAuth2UserRequest, OAuth2User> {
        // ...
    }
}

OpenID Connect 1.0 UserService

OidcUserServiceOAuth2UserService 的實作,支援 OpenID Connect 1.0 提供者。

當在 UserInfo 端點請求使用者屬性時,OidcUserService 利用 DefaultOAuth2UserService

如果您需要自訂 UserInfo 請求的預先處理或 UserInfo 回應的後續處理,您需要提供 OidcUserService.setOauth2UserService() 和自訂組態的 DefaultOAuth2UserService

無論您是自訂 OidcUserService 還是為 OpenID Connect 1.0 提供者提供您自己的 OAuth2UserService 實作,您都需要如下組態它

  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.oauth2Login(oauth2 -> oauth2
				.userInfoEndpoint(userInfo -> userInfo
				    .oidcUserService(this.oidcUserService())
				    ...
			    )
			);
		return http.build();
	}

	private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
		...
	}
}
@Configuration
@EnableWebSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            oauth2Login {
                userInfoEndpoint {
                    oidcUserService = oidcUserService()
                    // ...
                }
            }
        }
        return http.build()
    }

    private fun oidcUserService(): OAuth2UserService<OidcUserRequest, OidcUser> {
        // ...
    }
}

ID 權杖簽章驗證

OpenID Connect 1.0 驗證引入了 ID 權杖,這是一種安全權杖,包含關於最終使用者透過授權伺服器驗證的宣告 (當用戶端使用時)。

ID 權杖表示為 JSON Web 權杖 (JWT),且必須使用 JSON Web 簽章 (JWS) 簽署。

OidcIdTokenDecoderFactory 提供用於 OidcIdToken 簽章驗證的 JwtDecoder。預設演算法為 RS256,但在用戶端註冊期間指派時可能會有所不同。在這些情況下,您可以組態解析器以傳回為特定用戶端指派的預期 JWS 演算法。

JWS 演算法解析器是一個 Function,它接受 ClientRegistration 並傳回用戶端的預期 JwsAlgorithm,例如 SignatureAlgorithm.RS256MacAlgorithm.HS256

以下程式碼示範如何組態 OidcIdTokenDecoderFactory @Bean,使其預設為所有 ClientRegistration 實例的 MacAlgorithm.HS256

  • Java

  • Kotlin

@Bean
public JwtDecoderFactory<ClientRegistration> idTokenDecoderFactory() {
	OidcIdTokenDecoderFactory idTokenDecoderFactory = new OidcIdTokenDecoderFactory();
	idTokenDecoderFactory.setJwsAlgorithmResolver(clientRegistration -> MacAlgorithm.HS256);
	return idTokenDecoderFactory;
}
@Bean
fun idTokenDecoderFactory(): JwtDecoderFactory<ClientRegistration?> {
    val idTokenDecoderFactory = OidcIdTokenDecoderFactory()
    idTokenDecoderFactory.setJwsAlgorithmResolver { MacAlgorithm.HS256 }
    return idTokenDecoderFactory
}

對於基於 MAC 的演算法 (例如 HS256HS384HS512),對應於 client-idclient-secret 用作簽章驗證的對稱金鑰。

如果為 OpenID Connect 1.0 驗證組態了多個 ClientRegistration,則 JWS 演算法解析器可以評估提供的 ClientRegistration,以判斷要傳回哪個演算法。

然後,您可以繼續組態 登出