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();
	}

}