# 核心配置

## Spring 启动2.x示例

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

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

* [初始设置](#oauth2login-sample-initial-setup)

* [设置重定向URI](#oauth2login-sample-redirect-uri)

* [配置application.yml](#oauth2login-sample-application-config)

* [启动应用程序](#oauth2login-sample-boot-application)

### 初始设置

要使用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/)。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

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

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

### 设置重定向URI

重定向URI是应用程序中的路径，最终用户的用户代理在与Google进行身份验证并授予对同意页面上的OAuth客户端*（[在前一步中创建](#oauth2login-sample-initial-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/index.html#oauth2Client-client-registration)的唯一标识符。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |如果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**|在基本属性前缀之后是[客户登记](../client/index.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/index.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客户端](#oauth2login-sample-application-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自动配置类是`OAuth2ClientAutoConfiguration`。

它执行以下任务：

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

* 提供`WebSecurityConfigurerAdapter``@Configuration`并通过`httpSecurity.oauth2Login()`启用OAuth2.0登录。

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

* [注册一个ClientRegistrationRepository@ Bean](#oauth2login-register-clientregistrationrepository-bean)

* [提供一个WebSecurityConfigureRadapter](#oauth2login-provide-websecurityconfigureradapter)

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

### Register a ClientRegistrationRepository @Bean

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

Java

```
@Configuration
public class OAuth2LoginConfig {

	@Bean
	public ClientRegistrationRepository clientRegistrationRepository() {
		return new InMemoryClientRegistrationRepository(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(): ClientRegistrationRepository {
        return InMemoryClientRegistrationRepository(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()
    }
}
```

### 提供一个WebSecurityConfigureRadapter

下面的示例展示了如何使用`@EnableWebSecurity`提供`WebSecurityConfigurerAdapter`并通过`httpSecurity.oauth2Login()`启用OAuth2.0登录：

例2. OAuth2登录配置

Java

```
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests(authorize -> authorize
				.anyRequest().authenticated()
			)
			.oauth2Login(withDefaults());
	}
}
```

Kotlin

```
@EnableWebSecurity
class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() {

    override fun configure(http: HttpSecurity) {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2Login { }
        }
    }
}
```

### 完全覆盖自动配置

下面的示例展示了如何通过注册一个`ClientRegistrationRepository``@Bean`并提供一个`WebSecurityConfigurerAdapter`来完全覆盖自动配置。

例3.覆盖自动配置

Java

```
@Configuration
public class OAuth2LoginConfig {

	@EnableWebSecurity
	public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {

		@Override
		protected void configure(HttpSecurity http) throws Exception {
			http
				.authorizeHttpRequests(authorize -> authorize
					.anyRequest().authenticated()
				)
				.oauth2Login(withDefaults());
		}
	}

	@Bean
	public ClientRegistrationRepository clientRegistrationRepository() {
		return new InMemoryClientRegistrationRepository(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 {

    @EnableWebSecurity
    class OAuth2LoginSecurityConfig: WebSecurityConfigurerAdapter() {

        override fun configure(http: HttpSecurity) {
            http {
                authorizeRequests {
                    authorize(anyRequest, authenticated)
                }
                oauth2Login { }
            }
        }
    }

    @Bean
    fun clientRegistrationRepository(): ClientRegistrationRepository {
        return InMemoryClientRegistrationRepository(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()
    }
}
```

## Java 配置不需要 Spring 启动2.x

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

例4. OAuth2登录配置

Java

```
@Configuration
public class OAuth2LoginConfig {

	@EnableWebSecurity
	public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {

		@Override
		protected void configure(HttpSecurity http) throws Exception {
			http
				.authorizeHttpRequests(authorize -> authorize
					.anyRequest().authenticated()
				)
				.oauth2Login(withDefaults());
		}
	}

	@Bean
	public ClientRegistrationRepository clientRegistrationRepository() {
		return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
	}

	@Bean
	public OAuth2AuthorizedClientService authorizedClientService(
			ClientRegistrationRepository clientRegistrationRepository) {
		return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
	}

	@Bean
	public OAuth2AuthorizedClientRepository authorizedClientRepository(
			OAuth2AuthorizedClientService authorizedClientService) {
		return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);
	}

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

Kotlin

```
@Configuration
open class OAuth2LoginConfig {
    @EnableWebSecurity
    open class OAuth2LoginSecurityConfig : WebSecurityConfigurerAdapter() {
        override fun configure(http: HttpSecurity) {
            http {
                authorizeRequests {
                    authorize(anyRequest, authenticated)
                }
                oauth2Login { }
            }
        }
    }

    @Bean
    open fun clientRegistrationRepository(): ClientRegistrationRepository {
        return InMemoryClientRegistrationRepository(googleClientRegistration())
    }

    @Bean
    open fun authorizedClientService(
        clientRegistrationRepository: ClientRegistrationRepository?
    ): OAuth2AuthorizedClientService {
        return InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository)
    }

    @Bean
    open fun authorizedClientRepository(
        authorizedClientService: OAuth2AuthorizedClientService?
    ): OAuth2AuthorizedClientRepository {
        return AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService)
    }

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

XML

```
<http auto-config="true">
	<intercept-url pattern="/**" access="authenticated"/>
	<oauth2-login authorized-client-repository-ref="authorizedClientRepository"/>
</http>

<client-registrations>
	<client-registration registration-id="google"
						 client-id="google-client-id"
						 client-secret="google-client-secret"
						 provider-id="google"/>
</client-registrations>

<b:bean id="authorizedClientService"
		class="org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService"
		autowire="constructor"/>

<b:bean id="authorizedClientRepository"
		class="org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository">
	<b:constructor-arg ref="authorizedClientService"/>
</b:bean>
```

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