Advanced Configuration

OAuth 2.0 授权框架将 Protocol Endpoints 定义如下:

The OAuth 2.0 Authorization Framework defines the Protocol Endpoints as follows:

授权过程使用两个授权服务器端点(HTTP 资源):

The authorization process utilizes two authorization server endpoints (HTTP resources):

  • Authorization Endpoint: Used by the client to obtain authorization from the resource owner via user-agent redirection.

  • Token Endpoint: Used by the client to exchange an authorization grant for an access token, typically with client authentication.

以及一个客户端端点:

As well as one client endpoint:

  • Redirection Endpoint: Used by the authorization server to return responses containing authorization credentials to the client via the resource owner user-agent.

OpenID Connect 核心 1.0 规范将 UserInfo Endpoint 定义如下:

The OpenID Connect Core 1.0 specification defines the UserInfo Endpoint as follows:

UserInfo 端点是一个 OAuth 2.0 受保护资源,返回有关经过身份验证的最终用户的信息。为了获得有关最终用户请求的信息,客户端使用通过 OpenID Connect Authentication 获得的访问令牌,向 UserInfo 端点发出请求。这些信息通常由一个 JSON 对象表示,该对象包含一系列用于信息的名称-值对。

The UserInfo Endpoint is an OAuth 2.0 Protected Resource that returns claims about the authenticated end-user. To obtain the requested claims about the end-user, the client makes a request to the UserInfo Endpoint by using an access token obtained through OpenID Connect Authentication. These claims are normally represented by a JSON object that contains a collection of name-value pairs for the claims.

ServerHttpSecurity.oauth2Login() 提供了许多配置选项,用于定制 OAuth 2.0 登录。

ServerHttpSecurity.oauth2Login() provides a number of configuration options for customizing OAuth 2.0 Login.

以下代码显示了 oauth2Login() DSL 可用的完整配置选项:

The following code shows the complete configuration options available for the oauth2Login() DSL:

OAuth2 Login Configuration Options
  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
		http
			.oauth2Login(oauth2 -> oauth2
				.authenticationConverter(this.authenticationConverter())
				.authenticationMatcher(this.authenticationMatcher())
				.authenticationManager(this.authenticationManager())
				.authenticationSuccessHandler(this.authenticationSuccessHandler())
				.authenticationFailureHandler(this.authenticationFailureHandler())
				.clientRegistrationRepository(this.clientRegistrationRepository())
				.authorizedClientRepository(this.authorizedClientRepository())
				.authorizedClientService(this.authorizedClientService())
				.authorizationRequestResolver(this.authorizationRequestResolver())
				.authorizationRequestRepository(this.authorizationRequestRepository())
				.securityContextRepository(this.securityContextRepository())
			);

		return http.build();
	}
}
@Configuration
@EnableWebFluxSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        http {
            oauth2Login {
                authenticationConverter = authenticationConverter()
                authenticationMatcher = authenticationMatcher()
                authenticationManager = authenticationManager()
                authenticationSuccessHandler = authenticationSuccessHandler()
                authenticationFailureHandler = authenticationFailureHandler()
                clientRegistrationRepository = clientRegistrationRepository()
                authorizedClientRepository = authorizedClientRepository()
                authorizedClientService = authorizedClientService()
                authorizationRequestResolver = authorizationRequestResolver()
                authorizationRequestRepository = authorizationRequestRepository()
                securityContextRepository = securityContextRepository()
            }
        }

        return http.build()
    }
}

以下各节将详细介绍每个可用的配置选项:

The following sections go into more detail on each of the configuration options available:

OAuth 2.0 Login Page

默认情况下,OAuth 2.0 登录页是由 LoginPageGeneratingWebFilter 自动生成的。默认登录页显示每个配置的 OAuth 客户端及其 ClientRegistration.clientName 作为一个链接,该链接能够启动授权请求(或 OAuth 2.0 登录)。

By default, the OAuth 2.0 Login Page is auto-generated by the LoginPageGeneratingWebFilter. The default login page shows each configured OAuth Client with its ClientRegistration.clientName as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login).

为了使 LoginPageGeneratingWebFilter 显示已配置的 OAuth 客户端的链接,已注册的 ReactiveClientRegistrationRepository 也需要实现 Iterable<ClientRegistration>。请参阅 InMemoryReactiveClientRegistrationRepository 以备参考。

In order for LoginPageGeneratingWebFilter to show links for configured OAuth Clients, the registered ReactiveClientRegistrationRepository needs to also implement Iterable<ClientRegistration>. See InMemoryReactiveClientRegistrationRepository for reference.

每个 OAuth 客户端的链接目标默认为以下内容:

The link’s destination for each OAuth Client defaults to the following:

"/oauth2/authorization/{registrationId}"

以下行为示例:

The following line shows an example:

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

要覆盖默认登录页,请配置 exceptionHandling().authenticationEntryPoint() 和(可选)oauth2Login().authorizationRequestResolver()

To override the default login page, configure the exceptionHandling().authenticationEntryPoint() and (optionally) oauth2Login().authorizationRequestResolver().

下面的清单显示了一个示例:

The following listing shows an example:

OAuth2 Login Page Configuration
  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			.exceptionHandling(exceptionHandling -> exceptionHandling
				.authenticationEntryPoint(new RedirectServerAuthenticationEntryPoint("/login/oauth2"))
			)
			.oauth2Login(oauth2 -> oauth2
				.authorizationRequestResolver(this.authorizationRequestResolver())
			);

		return http.build();
	}

	private ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver() {
		ServerWebExchangeMatcher authorizationRequestMatcher =
				new PathPatternParserServerWebExchangeMatcher(
						"/login/oauth2/authorization/{registrationId}");

		return new DefaultServerOAuth2AuthorizationRequestResolver(
				this.clientRegistrationRepository(), authorizationRequestMatcher);
	}

	...
}
@Configuration
@EnableWebFluxSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        http {
            exceptionHandling {
                authenticationEntryPoint = RedirectServerAuthenticationEntryPoint("/login/oauth2")
            }
            oauth2Login {
                authorizationRequestResolver = authorizationRequestResolver()
            }
        }

        return http.build()
    }

    private fun authorizationRequestResolver(): ServerOAuth2AuthorizationRequestResolver {
        val authorizationRequestMatcher: ServerWebExchangeMatcher = PathPatternParserServerWebExchangeMatcher(
            "/login/oauth2/authorization/{registrationId}"
        )

        return DefaultServerOAuth2AuthorizationRequestResolver(
            clientRegistrationRepository(), authorizationRequestMatcher
        )
    }

    ...
}

您需要提供一个 @Controller 及其 @RequestMapping("/login/oauth2"),能够呈现自定义登录页面。

You need to provide a @Controller with a @RequestMapping("/login/oauth2") that is capable of rendering the custom login page.

如前所述,配置 oauth2Login().authorizationRequestResolver() 是可选的。但是,如果您选择定制它,请确保到每个 OAuth 客户端的链接与通过 ServerWebExchangeMatcher 提供的模式相匹配。

As noted earlier, configuring oauth2Login().authorizationRequestResolver() is optional. However, if you choose to customize it, ensure the link to each OAuth Client matches the pattern provided through the ServerWebExchangeMatcher.

以下行为示例:

The following line shows an example:

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

Redirection Endpoint

重定向端点由授权服务器用于通过资源所有者用户代理将授权响应(包含授权凭据)返回给客户端。

The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client via the Resource Owner user-agent.

OAuth 2.0 登录利用授权代码授予。因此,授权凭证就是授权代码。

OAuth 2.0 Login leverages the Authorization Code Grant. Therefore, the authorization credential is the authorization code.

默认授权响应重定向端点是 /login/oauth2/code/{registrationId}

The default Authorization Response redirection endpoint is /login/oauth2/code/{registrationId}.

如果您想要定制授权响应重定向端点,请按照以下示例中的说明进行配置:

If you would like to customize the Authorization Response redirection endpoint, configure it as shown in the following example:

Redirection Endpoint Configuration
  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			.oauth2Login(oauth2 -> oauth2
				.authenticationMatcher(new PathPatternParserServerWebExchangeMatcher("/login/oauth2/callback/{registrationId}"))
			);

		return http.build();
	}
}
@Configuration
@EnableWebFluxSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        http {
            oauth2Login {
                authenticationMatcher = PathPatternParserServerWebExchangeMatcher("/login/oauth2/callback/{registrationId}")
            }
        }

        return http.build()
    }
}

您还需要确保 ClientRegistration.redirectUri 与自定义授权响应重定向端点匹配。

You also need to ensure the ClientRegistration.redirectUri matches the custom Authorization Response redirection endpoint.

下面的清单显示了一个示例:

The following listing shows an example:

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

UserInfo Endpoint

UserInfo 终结点包括多个配置选项,如下小节所述:

The UserInfo Endpoint includes a number of configuration options, as described in the following sub-sections:

Mapping User Authorities

用户在 OAuth 2.0 提供商处成功认证后,OAuth2User.getAuthorities() (或 OidcUser.getAuthorities()) 包含从 OAuth2UserRequest.getAccessToken().getScopes() 中填充的授权列表,并在其之前加上 SCOPE_。这些授权可能被映射到 GrantedAuthority 实例的新集合,它会在完成认证时提供给 OAuth2AuthenticationToken

After the user successfully authenticates with the OAuth 2.0 Provider, the OAuth2User.getAuthorities() (or OidcUser.getAuthorities()) contains a list of granted authorities populated from OAuth2UserRequest.getAccessToken().getScopes() and prefixed with SCOPE_. These granted authorities may be mapped to a new set of GrantedAuthority instances, which will be supplied to OAuth2AuthenticationToken when completing the authentication.

OAuth2AuthenticationToken.getAuthorities() 用于授权请求,例如 hasRole('USER')hasRole('ADMIN') 中的请求。

OAuth2AuthenticationToken.getAuthorities() is used for authorizing requests, such as in hasRole('USER') or hasRole('ADMIN').

在映射用户权限时有几个选项可供选择:

There are a couple of options to choose from when mapping user authorities:

Using a GrantedAuthoritiesMapper

GrantedAuthoritiesMapper 具有被授予的权限列表,其中包含 OAuth2UserAuthority 类型和权限字符串 OAUTH2_USER(或 OidcUserAuthority 和权限字符串 OIDC_USER)的特殊权限。

The GrantedAuthoritiesMapper is given a list of granted authorities which contains a special authority of type OAuth2UserAuthority and the authority string OAUTH2_USER (or OidcUserAuthority and the authority string OIDC_USER).

注册一个 GrantedAuthoritiesMapper @Bean 以使其自动应用到配置中,如以下示例所示:

Register a GrantedAuthoritiesMapper @Bean to have it automatically applied to the configuration, as shown in the following example:

Granted Authorities Mapper Configuration
  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			...
			.oauth2Login(withDefaults());

		return http.build();
	}

	@Bean
	public 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
@EnableWebFluxSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        http {
            oauth2Login { }
        }

        return http.build()
    }

    @Bean
    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
    }
}

Delegation-based strategy with ReactiveOAuth2UserService

与使用 GrantedAuthoritiesMapper 相比,此策略更加高级,不过,它也更加灵活,因为它允许您访问 OAuth2UserRequestOAuth2User(使用 OAuth 2.0 UserService 时)或 OidcUserRequestOidcUser(使用 OpenID Connect 1.0 UserService 时)。

This strategy is advanced compared to using a GrantedAuthoritiesMapper, however, it’s also more flexible as it gives you access to the OAuth2UserRequest and OAuth2User (when using an OAuth 2.0 UserService) or OidcUserRequest and OidcUser (when using an OpenID Connect 1.0 UserService).

OAuth2UserRequest(和 OidcUserRequest)使您能访问关联的 OAuth2AccessToken,在 delegator 需要在为用户映射自定义授权之前从受保护资源中获取授权信息的情况下,此访问非常有用。

The OAuth2UserRequest (and OidcUserRequest) provides you access to the associated OAuth2AccessToken, which is very useful in the cases where the delegator needs to fetch authority information from a protected resource before it can map the custom authorities for the user.

以下示例展示了如何使用 OpenID Connect 1.0 UserService 实现和配置基于委派的策略:

The following example shows how to implement and configure a delegation-based strategy using an OpenID Connect 1.0 UserService:

ReactiveOAuth2UserService Configuration
  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			...
			.oauth2Login(withDefaults());

		return http.build();
	}

	@Bean
	public ReactiveOAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
		final OidcReactiveOAuth2UserService delegate = new OidcReactiveOAuth2UserService();

		return (userRequest) -> {
			// Delegate to the default implementation for loading a user
			return delegate.loadUser(userRequest)
					.flatMap((oidcUser) -> {
						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 Mono.just(oidcUser);
					});
		};
	}
}
@Configuration
@EnableWebFluxSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        http {
            oauth2Login { }
        }

        return http.build()
    }

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

        return ReactiveOAuth2UserService { userRequest ->
            // Delegate to the default implementation for loading a user
            delegate.loadUser(userRequest)
                .flatMap { oidcUser ->
                    val accessToken = userRequest.accessToken
                    val mappedAuthorities = mutableSetOf<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()
                    val mappedOidcUser = if (StringUtils.hasText(userNameAttributeName)) {
                        DefaultOidcUser(mappedAuthorities, oidcUser.idToken, oidcUser.userInfo, userNameAttributeName)
                    } else {
                        DefaultOidcUser(mappedAuthorities, oidcUser.idToken, oidcUser.userInfo)
                    }

                    Mono.just(mappedOidcUser)
                }
        }
    }
}

OAuth 2.0 UserService

DefaultReactiveOAuth2UserServiceReactiveOAuth2UserService 的实现,它支持标准 OAuth 2.0 提供商。

DefaultReactiveOAuth2UserService is an implementation of a ReactiveOAuth2UserService that supports standard OAuth 2.0 Provider’s.

ReactiveOAuth2UserService 从 UserInfo 端点(使用在授权流程期间授予客户端的访问令牌)获取最终用户(资源拥有者)用户属性并返回 AuthenticatedPrincipal,格式为 OAuth2User

ReactiveOAuth2UserService obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an AuthenticatedPrincipal in the form of an OAuth2User.

DefaultReactiveOAuth2UserService 在 UserInfo 端点请求用户属性时使用 WebClient

DefaultReactiveOAuth2UserService uses a WebClient when requesting the user attributes at the UserInfo Endpoint.

如果您需要定制 UserInfo 请求的预处理和/或 UserInfo 响应的后处理,您需要用自定义配置的 WebClientDefaultReactiveOAuth2UserService.setWebClient() 提供。

If you need to customize the pre-processing of the UserInfo Request and/or the post-handling of the UserInfo Response, you will need to provide DefaultReactiveOAuth2UserService.setWebClient() with a custom configured WebClient.

无论您定制 DefaultReactiveOAuth2UserService 还是提供 ReactiveOAuth2UserService 的自定义实现,您都需要按照以下示例中的说明进行配置:

Whether you customize DefaultReactiveOAuth2UserService or provide your own implementation of ReactiveOAuth2UserService, you’ll need to configure it as shown in the following example:

  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			...
			.oauth2Login(withDefaults());

		return http.build();
	}

	@Bean
	public ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
		...
	}
}
@Configuration
@EnableWebFluxSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        http {
            oauth2Login { }
        }

        return http.build()
    }

    @Bean
    fun oauth2UserService(): ReactiveOAuth2UserService<OAuth2UserRequest, OAuth2User> {
        // ...
    }
}

OpenID Connect 1.0 UserService

OidcReactiveOAuth2UserServiceReactiveOAuth2UserService 的实现,它支持 OpenID Connect 1.0 提供商。

OidcReactiveOAuth2UserService is an implementation of a ReactiveOAuth2UserService that supports OpenID Connect 1.0 Provider’s.

OidcReactiveOAuth2UserService 在 UserInfo 端点请求用户属性时利用 DefaultReactiveOAuth2UserService

The OidcReactiveOAuth2UserService leverages the DefaultReactiveOAuth2UserService when requesting the user attributes at the UserInfo Endpoint.

如果您需要定制 UserInfo 请求的预处理和/或 UserInfo 响应的后处理,您需要用自定义配置的 ReactiveOAuth2UserServiceOidcReactiveOAuth2UserService.setOauth2UserService() 提供。

If you need to customize the pre-processing of the UserInfo Request and/or the post-handling of the UserInfo Response, you will need to provide OidcReactiveOAuth2UserService.setOauth2UserService() with a custom configured ReactiveOAuth2UserService.

无论您定制 OidcReactiveOAuth2UserService 还是为 OpenID Connect 1.0 提供商提供 ReactiveOAuth2UserService 的自定义实现,您都需要按照以下示例中的说明进行配置:

Whether you customize OidcReactiveOAuth2UserService or provide your own implementation of ReactiveOAuth2UserService for OpenID Connect 1.0 Provider’s, you’ll need to configure it as shown in the following example:

  • Java

  • Kotlin

@Configuration
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			...
			.oauth2Login(withDefaults());

		return http.build();
	}

	@Bean
	public ReactiveOAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
		...
	}
}
@Configuration
@EnableWebFluxSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        http {
            oauth2Login { }
        }

        return http.build()
    }

    @Bean
    fun oidcUserService(): ReactiveOAuth2UserService<OidcUserRequest, OidcUser> {
        // ...
    }
}

ID Token Signature Verification

OpenID Connect 1.0 认证引入了 ID Token ,该 ID Token 是一个安全令牌,其中包含由授权服务器在客户端使用时对最终用户的认证索赔。

OpenID Connect 1.0 Authentication introduces the ID Token, which is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when used by a Client.

ID 令牌表示为 JSON Web Token(JWT),并且必须使用 JSON Web Signature(JWS)进行签名。

The ID Token is represented as a JSON Web Token (JWT) and MUST be signed using JSON Web Signature (JWS).

ReactiveOidcIdTokenDecoderFactory 提供了 ReactiveJwtDecoder,用于 OidcIdToken 签名验证。默认算法为 RS256,但在客户端注册期间分配时,可能不同。对于这些情况,可以配置解析器以返回为特定客户端分配的预期 JWS 算法。

The ReactiveOidcIdTokenDecoderFactory provides a ReactiveJwtDecoder used for OidcIdToken signature verification. The default algorithm is RS256 but may be different when assigned during client registration. For these cases, a resolver may be configured to return the expected JWS algorithm assigned for a specific client.

JWS 算法解析器是 Function,它接受 ClientRegistration,并为客户端返回预期 JwsAlgorithm,比如 SignatureAlgorithm.RS256MacAlgorithm.HS256

The JWS algorithm resolver is a Function that accepts a ClientRegistration and returns the expected JwsAlgorithm for the client, eg. SignatureAlgorithm.RS256 or MacAlgorithm.HS256

以下代码展示了如何配置 OidcIdTokenDecoderFactory @Bean,使其对所有 ClientRegistration 默认使用 MacAlgorithm.HS256

The following code shows how to configure the OidcIdTokenDecoderFactory @Bean to default to MacAlgorithm.HS256 for all ClientRegistration:

  • Java

  • Kotlin

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

对于诸如 HS256HS384HS512 的基于 MAC 的算法,与 client-id 对应的 client-secret 用于签名验证的对称密钥。

For MAC based algorithms such as HS256, HS384 or HS512, the client-secret corresponding to the client-id is used as the symmetric key for signature verification.

如果为 OpenID Connect 1.0 身份验证配置了多个 ClientRegistration,则 JWS 算法解析器可能会评估提供的 ClientRegistration 来确定要返回哪个算法。

If more than one ClientRegistration is configured for OpenID Connect 1.0 Authentication, the JWS algorithm resolver may evaluate the provided ClientRegistration to determine which algorithm to return.

然后,可以继续配置 logout

Then, you can proceed to configure logout.