# 核心配置

## Spring 启动 2.x 示例

Spring Boot2.x 为 OAuth2.0 登录带来了完整的自动配置功能。

本节展示如何使用*谷歌*作为*身份验证提供者*配置[**OAuth2.0 登录 WebFlux 样本 **](https://github.com/spring-projects/spring-security-samples/tree/5.6.x/reactive/webflux/java/oauth2/login)，并涵盖以下主题：

* [初始设置](#webflux-oauth2-login-sample-setup)

* [设置重定向 URI](#webflux-oauth2-login-sample-redirect)

* [configure`application.yml`]（#WebFlux-OAuth2-login-sample-config）

* [启动应用程序](#webflux-oauth2-login-sample-start)

### 初始设置

要使用 Google 的 OAuth2.0 身份验证系统进行登录，你必须在 Google API 控制台中设置一个项目，以获得 OAuth2.0 凭据。

|   |用于身份验证的[谷歌的 OAuth2.0 实现](https://developers.google.com/identity/protocols/OpenIDConnect)符合[OpenID Connect1.0](https://openid.net/connect/)规范，并且是[OpenID 认证](https://openid.net/certification/)。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

按照[OpenID 连接](https://developers.google.com/identity/protocols/OpenIDConnect)页面上的说明，从“设置 OAuth2.0”一节开始。

在完成“获取 OAuth2.0 凭据”说明之后，你应该有一个新的 OAuth 客户机，其凭据由一个客户机 ID 和一个客户机秘密组成。

### 设置重定向 URI

重定向 URI 是应用程序中的路径，终端用户的用户代理在与 Google 进行身份验证并授予对同意页面上的 OAuth 客户端 *（[在前一步中创建](#webflux-oauth2-login-sample-setup)）* 的访问权限后，会被重定向回应用程序中的路径。

在“设置重定向 URI”子节中，确保将**授权重定向 URI**字段设置为`[http://localhost:8080/login/oauth2/code/google](http://localhost:8080/login/oauth2/code/google)`。

|   |默认的重定向 URI 模板是`{baseUrl}/login/oauth2/code/{registrationId}`。<br/>***注册 ID***是[客户登记](../client/core.html#oauth2Client-client-registration)的唯一标识符。<br/>对于我们的示例，`registrationId`是`google`。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |如果 OAuth 客户端运行在代理服务器后面，建议检查[代理服务器配置](../../../features/exploits/http.html#http-proxy-server)以确保应用程序配置正确。<br/>此外，请参阅支持的[`URI`模板变量]（../client/Authorization-grants.html#OAuth2client-auth-code-redirect-uri）。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 配置`application.yml`

现在，你有了一个新的 OAuth 客户机和 Google，你需要将应用程序配置为使用*认证流程*的 OAuth 客户机。这样做：

1. 转到`application.yml`并设置以下配置：

   ```
   spring:
     security:
       oauth2:
         client:
           registration:	(1)
             google:	(2)
               client-id: google-client-id
               client-secret: google-client-secret
   ```

   例 1。OAuth 客户属性

   |**1**|`spring.security.oauth2.client.registration`是 OAuth 客户机属性的基本属性前缀。|
   |-----|--------------------------------------------------------------------------------------------------------------------------------------------------|
   |**2**|在基本属性前缀之后是[`ClientRegistration`]（../client/core.html#OAuth2client-client-registration）的 ID，例如 Google。|

2. 用前面创建的 OAuth2.0 凭据替换`client-id`和`client-secret`属性中的值。

### 启动应用程序

启动 Spring boot2.x 示例，然后转到`[http://localhost:8080](http://localhost:8080)`。然后，你将被重定向到默认的*自动生成*登录页面，该页面显示了 Google 的链接。

点击谷歌链接，然后你将被重定向到谷歌进行身份验证。

在使用谷歌帐户凭据进行身份验证后，显示给你的下一页是“同意”屏幕。同意屏幕要求你允许或拒绝访问你之前创建的 OAuth 客户端。单击**允许**授权 OAuth 客户端访问你的电子邮件地址和基本配置文件信息。

此时，OAuth 客户机从[用户信息端点](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo)检索你的电子邮件地址和基本配置文件信息，并建立经过身份验证的会话。

## Spring 启动 2.x 属性映射

下表概述了 Spring Boot2.x OAuth 客户机属性到[客户登记](../client/core.html#oauth2Client-client-registration)属性的映射。

|Spring 启动 2.x|                   ClientRegistration                   |
|--------------------------------------------------------------------------------------------|--------------------------------------------------------|
|`spring.security.oauth2.client.registration.*[registrationId]*`|                    `registrationId`                    |
|`spring.security.oauth2.client.registration.*[registrationId]*.client-id`|                       `clientId`                       |
|`spring.security.oauth2.client.registration.*[registrationId]*.client-secret`|                     `clientSecret`                     |
|`spring.security.oauth2.client.registration.*[registrationId]*.client-authentication-method`|              `clientAuthenticationMethod`              |
|`spring.security.oauth2.client.registration.*[registrationId]*.authorization-grant-type`|                `authorizationGrantType`                |
|`spring.security.oauth2.client.registration.*[registrationId]*.redirect-uri`|                     `redirectUri`                      |
|`spring.security.oauth2.client.registration.*[registrationId]*.scope`|                        `scopes`                        |
|`spring.security.oauth2.client.registration.*[registrationId]*.client-name`|                      `clientName`                      |
|`spring.security.oauth2.client.provider.*[providerId]*.authorization-uri`|           `providerDetails.authorizationUri`           |
|`spring.security.oauth2.client.provider.*[providerId]*.token-uri`|               `providerDetails.tokenUri`               |
|`spring.security.oauth2.client.provider.*[providerId]*.jwk-set-uri`|              `providerDetails.jwkSetUri`               |
|`spring.security.oauth2.client.provider.*[providerId]*.issuer-uri`|              `providerDetails.issuerUri`               |
|`spring.security.oauth2.client.provider.*[providerId]*.user-info-uri`|         `providerDetails.userInfoEndpoint.uri`         |
|`spring.security.oauth2.client.provider.*[providerId]*.user-info-authentication-method`|`providerDetails.userInfoEndpoint.authenticationMethod` |
|`spring.security.oauth2.client.provider.*[providerId]*.user-name-attribute`|`providerDetails.userInfoEndpoint.userNameAttributeName`|

|   |通过指定`spring.security.oauth2.client.provider.*[providerId]*.issuer-uri`属性，可以使用发现 OpenID Connect 提供者的[配置端点](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig)或授权服务器的[元数据端点](https://tools.ietf.org/html/rfc8414#section-3)来初始配置`ClientRegistration`。|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## CommonoAuth2Provider

`CommonOAuth2Provider`为许多著名的提供商预先定义了一组默认的客户端属性：Google、GitHub、Facebook 和 OKTA。

例如，对于提供者，`authorization-uri`、`token-uri`和`user-info-uri`不会经常更改。因此，为了减少所需的配置，提供默认值是有意义的。

如前所述，当我们[配置了一个 Google 客户端](#webflux-oauth2-login-sample-config)时，只需要`client-id`和`client-secret`属性。

下面的清单展示了一个示例：

```
spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: google-client-id
            client-secret: google-client-secret
```

|   |客户机属性的自动默认在这里无缝地工作，因为`registrationId`（`google`）匹配`GOOGLE``enum`（不区分大小写）中的`CommonOAuth2Provider`。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

对于可能希望指定不同的`registrationId`的情况，例如`google-login`，你仍然可以通过配置`provider`属性来利用客户机属性的自动违约。

下面的清单展示了一个示例：

```
spring:
  security:
    oauth2:
      client:
        registration:
          google-login:	(1)
            provider: google	(2)
            client-id: google-client-id
            client-secret: google-client-secret
```

|**1**|将`registrationId`设置为`google-login`。|
|-----|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|将`provider`属性设置为`google`，这将利用`CommonOAuth2Provider.GOOGLE.getBuilder()`中设置的客户机属性的自动违约。|

## 配置自定义提供程序属性

有一些 OAuth2.0 提供程序支持多租赁，这会导致每个租户（或子域）的协议端点不同。

例如，向 OKTA 注册的 OAuth 客户端被分配到特定的子域并具有自己的协议端点。

对于这些情况， Spring Boot2.x 为配置自定义提供程序属性提供了以下基本属性：`spring.security.oauth2.client.provider.*[providerId]*`。

下面的清单展示了一个示例：

```
spring:
  security:
    oauth2:
      client:
        registration:
          okta:
            client-id: okta-client-id
            client-secret: okta-client-secret
        provider:
          okta:	(1)
            authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize
            token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token
            user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo
            user-name-attribute: sub
            jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys
```

|**1**|基本属性（`spring.security.oauth2.client.provider.okta`）允许自定义配置协议端点位置。|
|-----|---------------------------------------------------------------------------------------------------------------------------------|

## 覆盖 Spring 启动 2.x 自动配置

OAuth 客户端支持的 Spring Boot2.x 自动配置类是`ReactiveOAuth2ClientAutoConfiguration`。

它执行以下任务：

* 从配置的 OAuth 客户机属性中寄存器`ReactiveClientRegistrationRepository``@Bean`组成的`ClientRegistration`。

* 注册`SecurityWebFilterChain``@Bean`并通过`serverHttpSecurity.oauth2Login()`启用 OAuth2.0 登录。

如果需要根据你的特定需求重写自动配置，可以通过以下方式执行：

* [注册一个重新激活的注册存储库 @ Bean](#webflux-oauth2-login-register-reactiveclientregistrationrepository-bean)

* [注册一个 SecurityWebFilterchain@ Bean](#webflux-oauth2-login-register-securitywebfilterchain-bean)

* [完全覆盖自动配置](#webflux-oauth2-login-completely-override-autoconfiguration)

### Register a ReactiveClientRegistrationRepository @Bean

下面的示例显示了如何注册`ReactiveClientRegistrationRepository``@Bean`:

爪哇

```
@Configuration
public class OAuth2LoginConfig {

	@Bean
	public ReactiveClientRegistrationRepository clientRegistrationRepository() {
		return new InMemoryReactiveClientRegistrationRepository(this.googleClientRegistration());
	}

	private ClientRegistration googleClientRegistration() {
		return ClientRegistration.withRegistrationId("google")
				.clientId("google-client-id")
				.clientSecret("google-client-secret")
				.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
				.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
				.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
				.scope("openid", "profile", "email", "address", "phone")
				.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
				.tokenUri("https://www.googleapis.com/oauth2/v4/token")
				.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
				.userNameAttributeName(IdTokenClaimNames.SUB)
				.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
				.clientName("Google")
				.build();
	}
}
```

Kotlin

```
@Configuration
class OAuth2LoginConfig {

    @Bean
    fun clientRegistrationRepository(): ReactiveClientRegistrationRepository {
        return InMemoryReactiveClientRegistrationRepository(googleClientRegistration())
    }

    private fun googleClientRegistration(): ClientRegistration {
        return ClientRegistration.withRegistrationId("google")
                .clientId("google-client-id")
                .clientSecret("google-client-secret")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
                .scope("openid", "profile", "email", "address", "phone")
                .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
                .tokenUri("https://www.googleapis.com/oauth2/v4/token")
                .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
                .userNameAttributeName(IdTokenClaimNames.SUB)
                .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
                .clientName("Google")
                .build()
    }
}
```

### Register a SecurityWebFilterChain @Bean

下面的示例显示了如何用`@EnableWebFluxSecurity`注册`SecurityWebFilterChain``@Bean`并通过`serverHttpSecurity.oauth2Login()`启用 OAuth2.0 登录：

例 2。OAuth2 登录配置

爪哇

```
@EnableWebFluxSecurity
public class OAuth2LoginSecurityConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			.authorizeExchange(authorize -> authorize
				.anyExchange().authenticated()
			)
			.oauth2Login(withDefaults());

		return http.build();
	}
}
```

Kotlin

```
@EnableWebFluxSecurity
class OAuth2LoginSecurityConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http {
            authorizeExchange {
                authorize(anyExchange, authenticated)
            }
            oauth2Login { }
        }
    }
}
```

### 完全覆盖自动配置

下面的示例展示了如何通过注册一个`ReactiveClientRegistrationRepository``@Bean`和一个`SecurityWebFilterChain``@Bean`来完全覆盖自动配置。

例 3。覆盖自动配置

爪哇

```
@EnableWebFluxSecurity
public class OAuth2LoginConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			.authorizeExchange(authorize -> authorize
				.anyExchange().authenticated()
			)
			.oauth2Login(withDefaults());

		return http.build();
	}

	@Bean
	public ReactiveClientRegistrationRepository clientRegistrationRepository() {
		return new InMemoryReactiveClientRegistrationRepository(this.googleClientRegistration());
	}

	private ClientRegistration googleClientRegistration() {
		return ClientRegistration.withRegistrationId("google")
				.clientId("google-client-id")
				.clientSecret("google-client-secret")
				.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
				.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
				.redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
				.scope("openid", "profile", "email", "address", "phone")
				.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
				.tokenUri("https://www.googleapis.com/oauth2/v4/token")
				.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
				.userNameAttributeName(IdTokenClaimNames.SUB)
				.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
				.clientName("Google")
				.build();
	}
}
```

Kotlin

```
@EnableWebFluxSecurity
class OAuth2LoginConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http {
            authorizeExchange {
                authorize(anyExchange, authenticated)
            }
            oauth2Login { }
        }
    }

    @Bean
    fun clientRegistrationRepository(): ReactiveClientRegistrationRepository {
        return InMemoryReactiveClientRegistrationRepository(googleClientRegistration())
    }

    private fun googleClientRegistration(): ClientRegistration {
        return ClientRegistration.withRegistrationId("google")
                .clientId("google-client-id")
                .clientSecret("google-client-secret")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
                .scope("openid", "profile", "email", "address", "phone")
                .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
                .tokenUri("https://www.googleapis.com/oauth2/v4/token")
                .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
                .userNameAttributeName(IdTokenClaimNames.SUB)
                .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
                .clientName("Google")
                .build()
    }
}
```

## 不需要 Spring boot2.x 的 爪哇 配置

如果你不能使用 Spring Boot2.x，并且希望在`CommonOAuth2Provider`中配置一个预定义的提供程序（例如，Google），请应用以下配置：

例 4。OAuth2 登录配置

Java

```
@EnableWebFluxSecurity
public class OAuth2LoginConfig {

	@Bean
	public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
		http
			.authorizeExchange(authorize -> authorize
				.anyExchange().authenticated()
			)
			.oauth2Login(withDefaults());

		return http.build();
	}

	@Bean
	public ReactiveClientRegistrationRepository clientRegistrationRepository() {
		return new InMemoryReactiveClientRegistrationRepository(this.googleClientRegistration());
	}

	@Bean
	public ReactiveOAuth2AuthorizedClientService authorizedClientService(
			ReactiveClientRegistrationRepository clientRegistrationRepository) {
		return new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);
	}

	@Bean
	public ServerOAuth2AuthorizedClientRepository authorizedClientRepository(
			ReactiveOAuth2AuthorizedClientService authorizedClientService) {
		return new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
	}

	private ClientRegistration googleClientRegistration() {
		return CommonOAuth2Provider.GOOGLE.getBuilder("google")
				.clientId("google-client-id")
				.clientSecret("google-client-secret")
				.build();
	}
}
```

Kotlin

```
@EnableWebFluxSecurity
class OAuth2LoginConfig {

    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http {
            authorizeExchange {
                authorize(anyExchange, authenticated)
            }
            oauth2Login { }
        }
    }

    @Bean
    fun clientRegistrationRepository(): ReactiveClientRegistrationRepository {
        return InMemoryReactiveClientRegistrationRepository(googleClientRegistration())
    }

    @Bean
    fun authorizedClientService(
        clientRegistrationRepository: ReactiveClientRegistrationRepository
    ): ReactiveOAuth2AuthorizedClientService {
        return InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository)
    }

    @Bean
    fun authorizedClientRepository(
        authorizedClientService: ReactiveOAuth2AuthorizedClientService
    ): ServerOAuth2AuthorizedClientRepository {
        return AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService)
    }

    private fun googleClientRegistration(): ClientRegistration {
        return CommonOAuth2Provider.GOOGLE.getBuilder("google")
                .clientId("google-client-id")
                .clientSecret("google-client-secret")
                .build()
    }
}
```

[OAuth2 登录](index.html)[高级配置](advanced.html)

