Spring Security

如果 Spring Security 在类路径中,则 web 应用默认是安全的。Spring Boot 依赖 Spring Security 的内容协商策略来决定是使用 httpBasic 还是 formLogin。要在 web 应用中添加方法级别的安全性,你还可以使用你期望的设置添加 @EnableMethodSecurity。更多信息可以在 Spring Security 参考指南 中找到。

默认的 UserDetailsService 有一个用户。用户名为 user,密码是随机生成的,在应用启动时会以 WARN 级别打印出来,如下例所示

Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35

This generated password is for development use only. Your security configuration must be updated before running your application in production.
如果你精细调整了日志配置,请确保 org.springframework.boot.autoconfigure.security 分类设置为记录 WARN 级别的消息。否则,默认密码将不会打印。

你可以通过提供 spring.security.user.namespring.security.user.password 来改变用户名和密码。

在 web 应用中默认提供的基本特性包括

你可以通过添加一个 bean 来提供一个不同的 AuthenticationEventPublisher

MVC 安全

默认安全配置在 SecurityAutoConfigurationUserDetailsServiceAutoConfiguration 中实现。SecurityAutoConfiguration 导入 SpringBootWebSecurityConfiguration 用于 web 安全,UserDetailsServiceAutoConfiguration 用于认证。

要完全关闭默认的 web 应用安全配置,包括 Actuator 安全,或结合多个 Spring Security 组件(如 OAuth2 Client 和 Resource Server),请添加一个 SecurityFilterChain 类型的 bean(这样做不会禁用 UserDetailsService 配置)。要同时关闭 UserDetailsService 配置,请添加一个 UserDetailsServiceAuthenticationProviderAuthenticationManager 类型的 bean。

当以下任何 Spring Security 模块在类路径中时,UserDetailsService 的自动配置也会退出:

  • spring-security-oauth2-client

  • spring-security-oauth2-resource-server

  • spring-security-saml2-service-provider

要在这些依赖之外使用 UserDetailsService,请定义你自己的 InMemoryUserDetailsManager bean。

可以通过添加自定义的 SecurityFilterChain bean 来覆盖访问规则。Spring Boot 提供了便利方法,可用于覆盖 Actuator 端点和静态资源的访问规则。EndpointRequest 可用于创建一个基于 management.endpoints.web.base-path 属性的 RequestMatcherPathRequest 可用于为常用位置的资源创建一个 RequestMatcher

WebFlux 安全

类似于 Spring MVC 应用,你可以通过添加 spring-boot-starter-security 依赖来保护你的 WebFlux 应用。默认的安全配置在 ReactiveSecurityAutoConfigurationReactiveUserDetailsServiceAutoConfiguration 中实现。ReactiveSecurityAutoConfiguration 导入 WebFluxSecurityConfiguration 用于 web 安全,UserDetailsServiceAutoConfiguration 用于认证。除了响应式 web 应用外,当使用 RSocket 时,后者也会自动配置。

要完全关闭默认的 web 应用安全配置,包括 Actuator 安全,请添加一个 WebFilterChainProxy 类型的 bean(这样做不会禁用 ReactiveUserDetailsService 配置)。要同时关闭 ReactiveUserDetailsService 配置,请添加一个 ReactiveUserDetailsServiceReactiveAuthenticationManager 类型的 bean。

当以下任何 Spring Security 模块在类路径中时,自动配置也会退出:

  • spring-security-oauth2-client

  • spring-security-oauth2-resource-server

要在这些依赖之外使用 ReactiveUserDetailsService,请定义你自己的 MapReactiveUserDetailsService bean。

可以通过添加自定义的 SecurityWebFilterChain bean 来配置访问规则以及使用多个 Spring Security 组件(如 OAuth 2 Client 和 Resource Server)。Spring Boot 提供了便利方法,可用于覆盖 Actuator 端点和静态资源的访问规则。EndpointRequest 可用于创建一个基于 management.endpoints.web.base-path 属性的 ServerWebExchangeMatcher

PathRequest 可用于为常用位置的资源创建一个 ServerWebExchangeMatcher

例如,你可以通过添加类似如下配置来定制你的安全配置

  • Java

  • Kotlin

import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration(proxyBeanMethods = false)
public class MyWebFluxSecurityConfiguration {

	@Bean
	public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
		http.authorizeExchange((exchange) -> {
			exchange.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
			exchange.pathMatchers("/foo", "/bar").authenticated();
		});
		http.formLogin(withDefaults());
		return http.build();
	}

}
import org.springframework.boot.autoconfigure.security.reactive.PathRequest
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.Customizer.withDefaults
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.web.server.SecurityWebFilterChain

@Configuration(proxyBeanMethods = false)
class MyWebFluxSecurityConfiguration {

	@Bean
	fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
		http.authorizeExchange { spec ->
			spec.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
			spec.pathMatchers("/foo", "/bar").authenticated()
		}
		http.formLogin(withDefaults())
		return http.build()
	}

}

OAuth2

OAuth2 是一个广泛使用的授权框架,Spring 提供了支持。

客户端

如果你的类路径中有 spring-security-oauth2-client,你可以利用一些自动配置来设置 OAuth2/Open ID Connect 客户端。此配置使用 OAuth2ClientProperties 下的属性。这些属性适用于 servlet 应用和响应式应用。

你可以在 spring.security.oauth2.client 前缀下注册多个 OAuth2 客户端和提供者,如下例所示

  • Properties 文件

  • YAML 文件

spring.security.oauth2.client.registration.my-login-client.client-id=abcd
spring.security.oauth2.client.registration.my-login-client.client-secret=password
spring.security.oauth2.client.registration.my-login-client.client-name=Client for OpenID Connect
spring.security.oauth2.client.registration.my-login-client.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-login-client.scope=openid,profile,email,phone,address
spring.security.oauth2.client.registration.my-login-client.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.my-login-client.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-login-client.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-1.client-id=abcd
spring.security.oauth2.client.registration.my-client-1.client-secret=password
spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-uri={baseUrl}/authorized/user
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-2.client-id=abcd
spring.security.oauth2.client.registration.my-client-2.client-secret=password
spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-uri={baseUrl}/authorized/email
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=client_secret_basic
spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=https://my-auth-server.com/oauth2/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server.com/oauth2/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server.com/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=https://my-auth-server.com/oauth2/jwks
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name
spring:
  security:
    oauth2:
      client:
        registration:
          my-login-client:
            client-id: "abcd"
            client-secret: "password"
            client-name: "Client for OpenID Connect"
            provider: "my-oauth-provider"
            scope: "openid,profile,email,phone,address"
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            client-authentication-method: "client_secret_basic"
            authorization-grant-type: "authorization_code"

          my-client-1:
            client-id: "abcd"
            client-secret: "password"
            client-name: "Client for user scope"
            provider: "my-oauth-provider"
            scope: "user"
            redirect-uri: "{baseUrl}/authorized/user"
            client-authentication-method: "client_secret_basic"
            authorization-grant-type: "authorization_code"

          my-client-2:
            client-id: "abcd"
            client-secret: "password"
            client-name: "Client for email scope"
            provider: "my-oauth-provider"
            scope: "email"
            redirect-uri: "{baseUrl}/authorized/email"
            client-authentication-method: "client_secret_basic"
            authorization-grant-type: "authorization_code"

        provider:
          my-oauth-provider:
            authorization-uri: "https://my-auth-server.com/oauth2/authorize"
            token-uri: "https://my-auth-server.com/oauth2/token"
            user-info-uri: "https://my-auth-server.com/userinfo"
            user-info-authentication-method: "header"
            jwk-set-uri: "https://my-auth-server.com/oauth2/jwks"
            user-name-attribute: "name"

对于支持 OpenID Connect discovery 的 OpenID Connect 提供者,配置可以进一步简化。提供者需要配置 issuer-uri,这是它声称作为其 Issuer Identifier 的 URI。例如,如果提供的 issuer-uri 是 "https://example.com",则会向 "https://example.com/.well-known/openid-configuration" 发送 "OpenID Provider Configuration Request"。结果应为 "OpenID Provider Configuration Response"。以下示例展示了如何使用 issuer-uri 配置 OpenID Connect 提供者

  • Properties 文件

  • YAML 文件

spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
spring:
  security:
    oauth2:
      client:
        provider:
          oidc-provider:
            issuer-uri: "https://dev-123456.oktapreview.com/oauth2/default/"

默认情况下,Spring Security 的 OAuth2LoginAuthenticationFilter 只处理匹配 /login/oauth2/code/* 的 URL。如果你想定制 redirect-uri 使用不同的模式,你需要提供配置来处理该自定义模式。例如,对于 servlet 应用,你可以添加一个类似于以下配置的你自己的 SecurityFilterChain

  • Java

  • Kotlin

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
public class MyOAuthClientConfiguration {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests((requests) -> requests
				.anyRequest().authenticated()
			)
			.oauth2Login((login) -> login
				.redirectionEndpoint((endpoint) -> endpoint
					.baseUri("/login/oauth2/callback/*")
				)
			);
		return http.build();
	}

}
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.invoke
import org.springframework.security.web.SecurityFilterChain

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
open class MyOAuthClientConfiguration {

	@Bean
	open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
		http {
			authorizeHttpRequests {
				authorize(anyRequest, authenticated)
			}
			oauth2Login {
				redirectionEndpoint {
					baseUri = "/login/oauth2/callback/*"
				}
			}
		}
		return http.build()
	}

}
Spring Boot 自动配置一个 InMemoryOAuth2AuthorizedClientService,Spring Security 使用它来管理客户端注册。InMemoryOAuth2AuthorizedClientService 功能有限,我们建议仅在开发环境中使用它。对于生产环境,请考虑使用 JdbcOAuth2AuthorizedClientService 或创建你自己的 OAuth2AuthorizedClientService 实现。

常用提供者的 OAuth2 客户端注册

对于常用的 OAuth2 和 OpenID 提供者,包括 Google, Github, Facebook 和 Okta,我们提供了一组默认提供者配置(分别为 google, github, facebookokta)。

如果你不需要定制这些提供者,可以将 provider 属性设置为需要推断默认配置的提供者。此外,如果客户端注册的 key 与默认支持的提供者匹配,Spring Boot 也会推断出来。

换句话说,以下示例中的两个配置都使用 Google 提供者

  • Properties 文件

  • YAML 文件

spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=google
spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-secret=password
spring:
  security:
    oauth2:
      client:
        registration:
          my-client:
            client-id: "abcd"
            client-secret: "password"
            provider: "google"
          google:
            client-id: "abcd"
            client-secret: "password"

资源服务器

如果你的类路径中有 spring-security-oauth2-resource-server,Spring Boot 可以设置一个 OAuth2 资源服务器。对于 JWT 配置,需要指定 JWK Set URI 或 OIDC Issuer URI,如下例所示

  • Properties 文件

  • YAML 文件

spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: "https://example.com/oauth2/default/v1/keys"
  • Properties 文件

  • YAML 文件

spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: "https://dev-123456.oktapreview.com/oauth2/default/"
如果授权服务器不支持 JWK Set URI,你可以使用用于验证 JWT 签名的公钥来配置资源服务器。这可以通过 spring.security.oauth2.resourceserver.jwt.public-key-location 属性来完成,其值需要指向一个包含 PEM 编码的 x509 格式公钥的文件。

spring.security.oauth2.resourceserver.jwt.audiences 属性可用于指定 JWT 中 aud claim 的期望值。例如,要求 JWT 包含一个值为 my-audienceaud claim

  • Properties 文件

  • YAML 文件

spring.security.oauth2.resourceserver.jwt.audiences[0]=my-audience
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          audiences:
            - "my-audience"

这些属性同样适用于 servlet 应用和响应式应用。或者,你可以为 servlet 应用定义自己的 JwtDecoder bean,或为响应式应用定义一个 ReactiveJwtDecoder

如果使用不透明令牌 (opaque tokens) 而非 JWT,你可以配置以下属性通过内省 (introspection) 来验证令牌

  • Properties 文件

  • YAML 文件

spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://example.com/check-token
spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id
spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret
spring:
  security:
    oauth2:
      resourceserver:
        opaquetoken:
          introspection-uri: "https://example.com/check-token"
          client-id: "my-client-id"
          client-secret: "my-client-secret"

同样,这些属性适用于 servlet 应用和响应式应用。或者,你可以为 servlet 应用定义自己的 OpaqueTokenIntrospector bean,或为响应式应用定义一个 ReactiveOpaqueTokenIntrospector

授权服务器

如果你的类路径中有 spring-security-oauth2-authorization-server,你可以利用一些自动配置来设置一个基于 Servlet 的 OAuth2 授权服务器。

你可以在 spring.security.oauth2.authorizationserver.client 前缀下注册多个 OAuth2 客户端,如下例所示

  • Properties 文件

  • YAML 文件

spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-id=abcd
spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-secret={noop}secret1
spring.security.oauth2.authorizationserver.client.my-client-1.registration.client-authentication-methods[0]=client_secret_basic
spring.security.oauth2.authorizationserver.client.my-client-1.registration.authorization-grant-types[0]=authorization_code
spring.security.oauth2.authorizationserver.client.my-client-1.registration.authorization-grant-types[1]=refresh_token
spring.security.oauth2.authorizationserver.client.my-client-1.registration.redirect-uris[0]=https://my-client-1.com/login/oauth2/code/abcd
spring.security.oauth2.authorizationserver.client.my-client-1.registration.redirect-uris[1]=https://my-client-1.com/authorized
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[0]=openid
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[1]=profile
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[2]=email
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[3]=phone
spring.security.oauth2.authorizationserver.client.my-client-1.registration.scopes[4]=address
spring.security.oauth2.authorizationserver.client.my-client-1.require-authorization-consent=true
spring.security.oauth2.authorizationserver.client.my-client-1.token.authorization-code-time-to-live=5m
spring.security.oauth2.authorizationserver.client.my-client-1.token.access-token-time-to-live=10m
spring.security.oauth2.authorizationserver.client.my-client-1.token.access-token-format=reference
spring.security.oauth2.authorizationserver.client.my-client-1.token.reuse-refresh-tokens=false
spring.security.oauth2.authorizationserver.client.my-client-1.token.refresh-token-time-to-live=30m
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-id=efgh
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-secret={noop}secret2
spring.security.oauth2.authorizationserver.client.my-client-2.registration.client-authentication-methods[0]=client_secret_jwt
spring.security.oauth2.authorizationserver.client.my-client-2.registration.authorization-grant-types[0]=client_credentials
spring.security.oauth2.authorizationserver.client.my-client-2.registration.scopes[0]=user.read
spring.security.oauth2.authorizationserver.client.my-client-2.registration.scopes[1]=user.write
spring.security.oauth2.authorizationserver.client.my-client-2.jwk-set-uri=https://my-client-2.com/jwks
spring.security.oauth2.authorizationserver.client.my-client-2.token-endpoint-authentication-signing-algorithm=RS256
spring:
  security:
    oauth2:
      authorizationserver:
        client:
          my-client-1:
            registration:
              client-id: "abcd"
              client-secret: "{noop}secret1"
              client-authentication-methods:
                - "client_secret_basic"
              authorization-grant-types:
                - "authorization_code"
                - "refresh_token"
              redirect-uris:
                - "https://my-client-1.com/login/oauth2/code/abcd"
                - "https://my-client-1.com/authorized"
              scopes:
                - "openid"
                - "profile"
                - "email"
                - "phone"
                - "address"
            require-authorization-consent: true
            token:
              authorization-code-time-to-live: 5m
              access-token-time-to-live: 10m
              access-token-format: "reference"
              reuse-refresh-tokens: false
              refresh-token-time-to-live: 30m
          my-client-2:
            registration:
              client-id: "efgh"
              client-secret: "{noop}secret2"
              client-authentication-methods:
                - "client_secret_jwt"
              authorization-grant-types:
                - "client_credentials"
              scopes:
                - "user.read"
                - "user.write"
            jwk-set-uri: "https://my-client-2.com/jwks"
            token-endpoint-authentication-signing-algorithm: "RS256"
client-secret 属性必须采用配置的 PasswordEncoder 可以匹配的格式。默认的 PasswordEncoder 实例是通过 PasswordEncoderFactories.createDelegatingPasswordEncoder() 创建的。

Spring Boot 为 Spring Authorization Server 提供的自动配置旨在帮助快速入门。大多数应用将需要定制,并且会想要定义几个 bean 来覆盖自动配置。

以下组件可以被定义为 bean 来覆盖特定于 Spring Authorization Server 的自动配置

Spring Boot 自动配置一个 InMemoryRegisteredClientRepository,Spring Authorization Server 使用它来管理注册的客户端。InMemoryRegisteredClientRepository 功能有限,我们建议仅在开发环境中使用它。对于生产环境,请考虑使用 JdbcRegisteredClientRepository 或创建你自己的 RegisteredClientRepository 实现。

更多信息可以在 Spring Authorization Server 参考指南入门 (Getting Started) 章节中找到。

SAML 2.0

依赖方 (Relying Party)

如果你的类路径中有 `spring-security-saml2-service-provider`,你可以利用一些自动配置来设置 SAML 2.0 依赖方。Saml2RelyingPartyProperties 下的属性用于此配置。

依赖方注册代表了身份提供者 (IDP) 和服务提供者 (SP) 之间的配对配置。你可以在 spring.security.saml2.relyingparty 前缀下注册多个依赖方,如下例所示

  • Properties 文件

  • YAML 文件

spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party1.decryption.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party1.decryption.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.url=https://myapp/logout/saml2/slo
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.response-url=https://remoteidp2.slo.url
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.binding=POST
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.verification.credentials[0].certificate-location=path-to-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.entity-id=remote-idp-entity-id1
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.sso-url=https://remoteidp1.sso.url
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party2.decryption.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party2.decryption.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.verification.credentials[0].certificate-location=path-to-other-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.entity-id=remote-idp-entity-id2
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.sso-url=https://remoteidp2.sso.url
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.url=https://remoteidp2.slo.url
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.response-url=https://myapp/logout/saml2/slo
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.binding=POST
spring:
  security:
    saml2:
      relyingparty:
        registration:
          my-relying-party1:
            signing:
              credentials:
              - private-key-location: "path-to-private-key"
                certificate-location: "path-to-certificate"
            decryption:
              credentials:
              - private-key-location: "path-to-private-key"
                certificate-location: "path-to-certificate"
            singlelogout:
               url: "https://myapp/logout/saml2/slo"
               response-url: "https://remoteidp2.slo.url"
               binding: "POST"
            assertingparty:
              verification:
                credentials:
                - certificate-location: "path-to-verification-cert"
              entity-id: "remote-idp-entity-id1"
              sso-url: "https://remoteidp1.sso.url"

          my-relying-party2:
            signing:
              credentials:
              - private-key-location: "path-to-private-key"
                certificate-location: "path-to-certificate"
            decryption:
              credentials:
              - private-key-location: "path-to-private-key"
                certificate-location: "path-to-certificate"
            assertingparty:
              verification:
                credentials:
                - certificate-location: "path-to-other-verification-cert"
              entity-id: "remote-idp-entity-id2"
              sso-url: "https://remoteidp2.sso.url"
              singlelogout:
                url: "https://remoteidp2.slo.url"
                response-url: "https://myapp/logout/saml2/slo"
                binding: "POST"

对于 SAML2 注销,默认情况下,Spring Security 的 Saml2LogoutRequestFilterSaml2LogoutResponseFilter 只处理匹配 /logout/saml2/slo 的 URL。如果你想自定义 AP 发起的注销请求发送到的 url 或 AP 发送注销响应的 response-url,使用不同的模式,你需要提供配置来处理该自定义模式。例如,对于 servlet 应用,你可以添加一个类似于以下配置的你自己的 SecurityFilterChain

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration(proxyBeanMethods = false)
public class MySamlRelyingPartyConfiguration {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
		http.saml2Login(withDefaults());
		http.saml2Logout((saml2) -> saml2.logoutRequest((request) -> request.logoutUrl("/SLOService.saml2"))
			.logoutResponse((response) -> response.logoutUrl("/SLOService.saml2")));
		return http.build();
	}

}