对于最新的稳定版本,请使用 Spring Authorization Server 1.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Authorization Server 1.3.1Spring中文文档

如果您刚刚开始使用 Spring Authorization Server,以下部分将指导您创建第一个应用程序。Spring中文文档

系统要求

Spring Authorization Server 需要 Java 17 或更高版本的运行时环境。Spring中文文档

安装 Spring 授权服务器

Spring Authorization Server 可以在您已经使用 Spring Security 的任何地方使用。Spring中文文档

开始使用 Spring Authorization Server 的最简单方法是创建基于 Spring Boot 的应用程序。 可以使用 start.spring.io 生成基本项目,也可以使用默认授权服务器示例作为指南。 然后将Spring Boot的Spring Authorization Server启动器添加为依赖项:Spring中文文档

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
implementation "org.springframework.boot:spring-boot-starter-oauth2-authorization-server"
有关将 Spring Boot 与 Maven 或 Gradle 配合使用的更多信息,请参阅安装 Spring Boot

或者,您可以使用以下示例添加不带 Spring Boot 的 Spring 授权服务器:Spring中文文档

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-authorization-server</artifactId>
    <version>1.2.5</version>
</dependency>
implementation "org.springframework.security:spring-security-oauth2-authorization-server:1.2.5"
有关将 Spring Boot 与 Maven 或 Gradle 配合使用的更多信息,请参阅安装 Spring Boot

开发您的第一个应用程序

首先,您需要将所需的最小组件定义为 .使用依赖项时,定义以下属性,Spring Boot 将为您提供必要的定义:@Beanspring-boot-starter-oauth2-authorization-server@BeanSpring中文文档

application.yml
server:
  port: 9000

logging:
  level:
    org.springframework.security: trace

spring:
  security:
    user:
      name: user
      password: password
    oauth2:
      authorizationserver:
        client:
          oidc-client:
            registration:
              client-id: "oidc-client"
              client-secret: "{noop}secret"
              client-authentication-methods:
                - "client_secret_basic"
              authorization-grant-types:
                - "authorization_code"
                - "refresh_token"
              redirect-uris:
                - "http://127.0.0.1:8080/login/oauth2/code/oidc-client"
              post-logout-redirect-uris:
                - "http://127.0.0.1:8080/"
              scopes:
                - "openid"
                - "profile"
            require-authorization-consent: true
除了入门体验之外,大多数用户还需要自定义默认配置。下一节将演示如何自己提供所有必需的 Bean。
除了入门体验之外,大多数用户还需要自定义默认配置。下一节将演示如何自己提供所有必需的 Bean。

定义所需的组件

如果要自定义默认配置(无论是否使用 Spring Boot),可以在 Spring 中将所需的最小组件定义为 .@Bean@ConfigurationSpring中文文档

这些组件可以定义如下:Spring中文文档

SecurityConfig.java
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;

import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean (1)
	@Order(1)
	public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
			throws Exception {
		OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
		http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
			.oidc(Customizer.withDefaults());	// Enable OpenID Connect 1.0
		http
			// Redirect to the login page when not authenticated from the
			// authorization endpoint
			.exceptionHandling((exceptions) -> exceptions
				.defaultAuthenticationEntryPointFor(
					new LoginUrlAuthenticationEntryPoint("/login"),
					new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
				)
			)
			// Accept access tokens for User Info and/or Client Registration
			.oauth2ResourceServer((resourceServer) -> resourceServer
				.jwt(Customizer.withDefaults()));

		return http.build();
	}

	@Bean (2)
	@Order(2)
	public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
			throws Exception {
		http
			.authorizeHttpRequests((authorize) -> authorize
				.anyRequest().authenticated()
			)
			// Form login handles the redirect to the login page from the
			// authorization server filter chain
			.formLogin(Customizer.withDefaults());

		return http.build();
	}

	@Bean (3)
	public UserDetailsService userDetailsService() {
		UserDetails userDetails = User.withDefaultPasswordEncoder()
				.username("user")
				.password("password")
				.roles("USER")
				.build();

		return new InMemoryUserDetailsManager(userDetails);
	}

	@Bean (4)
	public RegisteredClientRepository registeredClientRepository() {
		RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
				.clientId("oidc-client")
				.clientSecret("{noop}secret")
				.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
				.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
				.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
				.redirectUri("http://127.0.0.1:8080/login/oauth2/code/oidc-client")
				.postLogoutRedirectUri("http://127.0.0.1:8080/")
				.scope(OidcScopes.OPENID)
				.scope(OidcScopes.PROFILE)
				.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
				.build();

		return new InMemoryRegisteredClientRepository(oidcClient);
	}

	@Bean (5)
	public JWKSource<SecurityContext> jwkSource() {
		KeyPair keyPair = generateRsaKey();
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		RSAKey rsaKey = new RSAKey.Builder(publicKey)
				.privateKey(privateKey)
				.keyID(UUID.randomUUID().toString())
				.build();
		JWKSet jwkSet = new JWKSet(rsaKey);
		return new ImmutableJWKSet<>(jwkSet);
	}

	private static KeyPair generateRsaKey() { (6)
		KeyPair keyPair;
		try {
			KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
			keyPairGenerator.initialize(2048);
			keyPair = keyPairGenerator.generateKeyPair();
		}
		catch (Exception ex) {
			throw new IllegalStateException(ex);
		}
		return keyPair;
	}

	@Bean (7)
	public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
		return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
	}

	@Bean (8)
	public AuthorizationServerSettings authorizationServerSettings() {
		return AuthorizationServerSettings.builder().build();
	}

}

这是快速入门的最低配置。若要了解每个组件的用途,请参阅以下说明:Spring中文文档

1 协议端点的 Spring Security 过滤器链。
2 用于身份验证的 Spring Security 过滤器链。
3 UserDetailsService 的一个实例,用于检索用户进行身份验证。
4 用于管理客户端的 RegisteredClientRepository 的实例。
5 用于对访问令牌进行签名的实例。com.nimbusds.jose.jwk.source.JWKSource
6 用于创建上述内容的启动时生成的密钥的实例。java.security.KeyPairJWKSource
7 用于解码签名访问令牌的 JwtDecoder 实例。
8 用于配置 Spring Authorization Server 的 AuthorizationServerSettings 实例。
1 协议端点的 Spring Security 过滤器链。
2 用于身份验证的 Spring Security 过滤器链。
3 UserDetailsService 的一个实例,用于检索用户进行身份验证。
4 用于管理客户端的 RegisteredClientRepository 的实例。
5 用于对访问令牌进行签名的实例。com.nimbusds.jose.jwk.source.JWKSource
6 用于创建上述内容的启动时生成的密钥的实例。java.security.KeyPairJWKSource
7 用于解码签名访问令牌的 JwtDecoder 实例。
8 用于配置 Spring Authorization Server 的 AuthorizationServerSettings 实例。