Spring Security

如果 {url-spring-security-site}[Spring Security] 在类路径中,那么会默认保护 Web 应用程序。Spring Boot 依靠 Spring Security 的内容协商策略来确定是否使用 httpBasicformLogin。要向 Web 应用程序添加方法级安全性,你还可以使用所需设置添加 @EnableGlobalMethodSecurity。有关更多信息,请参见 {url-spring-security-docs}/servlet/authorization/method-security.html[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 应用程序中默认获得的基本功能有:

  • 一个 UserDetailsService(或者在 WebFlux 应用程序中为 ReactiveUserDetailsService)bean 具有内存存储和一个带有生成密码的单个用户(请参见 SecurityProperties.User 以了解用户的属性)。

  • 整个应用程序的基于表单的登录或 HTTP 基本安全(取决于请求中的 Accept 头),包括 actuator 端点(如果 actuator 在类路径中)。

  • 用于发布身份验证事件的 DefaultAuthenticationEventPublisher

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

MVC Security

默认安全配置在 SecurityAutoConfigurationUserDetailsServiceAutoConfiguration 中实现。SecurityAutoConfiguration 导入 SpringBootWebSecurityConfiguration 以实现 Web 安全,UserDetailsServiceAutoConfiguration 配置身份验证(这也与非 Web 应用程序相关)。

要完全关闭默认 Web 应用程序安全配置或组合多个 Spring Security 组件(例如 OAuth2 Client 和资源服务器),请添加 SecurityFilterChain 类型的 bean(这样做不会禁用 UserDetailsService 配置或 Actuator 的安全性)。要同时关闭 UserDetailsService 配置,你可以添加 UserDetailsServiceAuthenticationProviderAuthenticationManager 类型的 bean。

UserDetailsService 的自动配置也会支持类路径中的任何一个 Spring Security 模块:

  • spring-security-oauth2-client

  • spring-security-oauth2-resource-server

  • spring-security-saml2-service-provider

除了上述一个或多个依赖项之外,要使用 UserDetailsService,请定义你自己的 InMemoryUserDetailsManager Bean。

可以通过添加自定义 SecurityFilterChain Bean 来覆盖访问规则。Spring Boot 提供了可用于覆盖执行器端点和静态资源访问规则的便捷方法。EndpointRequest 可用于创建基于 configprop:management.endpoints.web.base-path[] 属性的 RequestMatcherPathRequest 可用于为常用位置中的资源创建 RequestMatcher

WebFlux Security

与 Spring MVC 应用程序类似,你可以通过添加 spring-boot-starter-security 依赖项来保护你的 WebFlux 应用程序。默认安全配置在 ReactiveSecurityAutoConfigurationUserDetailsServiceAutoConfiguration 中实现。ReactiveSecurityAutoConfiguration 为 web 安全导入 WebFluxSecurityConfigurationUserDetailsServiceAutoConfiguration 配置身份验证(在非 web 应用程序中这也相关)。

要完全关闭默认的 Web 应用程序安全配置,您可以添加类型为 WebFilterChainProxy 的 Bean(这样做不会禁用 UserDetailsService 配置或执行器的安全)。要关闭 UserDetailsService 配置,您可以添加 ReactiveUserDetailsServiceReactiveAuthenticationManager 类型的 Bean。

当类路径上含有以下任一 Spring Security 模块时,自动配置也将退回:

  • spring-security-oauth2-client

  • spring-security-oauth2-resource-server

要额外使用 ReactiveUserDetailsService 而非其中的一个或多个依赖项,请定义您自己的 MapReactiveUserDetailsService Bean。

可以通过添加自定义 SecurityWebFilterChain Bean,来配置访问规则和多个 Spring Security 组件(例如 OAuth 2 客户端和资源服务器)的使用。Spring Boot 提供了可用于替代执行器端点和静态资源的访问规则的便捷方法。EndpointRequest 可用于创建基于 configprop:management.endpoints.web.base-path[] 属性的 ServerWebExchangeMatcher

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

例如,您可以通过添加类似以下内容的方式自定义安全配置:

OAuth2

OAuth2 是得到 Spring 支持的广泛应用的授权框架。

Client

如果类路径上存在 spring-security-oauth2-client,您可以利用某些自动配置来设置 OAuth2/Open ID Connect 客户端。此配置使用 OAuth2ClientProperties 下的属性。这些属性同时适用于 Servlet 和响应式应用程序。

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

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 进行配置,它是断言其颁发者标识符的 URI。例如,如果提供的 issuer-uri 是“https://example.com”,那么将向“https://example.com/.well-known/openid-configuration”发出“OpenID 提供程序配置请求”。结果预计为“OpenID 提供程序配置响应”。以下示例显示如何使用 issuer-uri 配置 OpenID Connect 提供程序:

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

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

OAuth2 Client Registration for Common Providers

对于包括 Google、Github、Facebook 和 Okta 在内的常见的 OAuth2 和 OpenID 提供程序,我们提供了一组提供程序默认值(分别为 googlegithubfacebookokta)。

如果您无需自定义这些提供程序,则可以将 provider 属性设置为需要从中推断默认值的那个属性。此外,如果客户端注册的密钥匹配默认支持的提供程序,Spring Boot 也推断该密钥。

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

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

Resource Server

如果类路径上存在 spring-security-oauth2-resource-server,Spring Boot 可以设置 OAuth2 资源服务器。对于 JWT 配置,需要指定 JWK Set URI 或 OIDC 颁发者 URI,如下面的示例所示:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: "https://example.com/oauth2/default/v1/keys"
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: "https://dev-123456.oktapreview.com/oauth2/default/"

如果授权服务器不支持 JWK Set URI,则可以使用用于验证 JWT 签名的公钥来配置资源服务器。可以使用 configprop:spring.security.oauth2.resourceserver.jwt.public-key-location[] 属性来执行此操作,其中值需要指向包含 PEM 编码的 x509 格式的公钥的文件。

可以使用 configprop:spring.security.oauth2.resourceserver.jwt.audiences[] 属性来指定 JWT 中 aud 声明的预期值。例如,要求 JWT 包含具有 my-audience 值的 aud 声明:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          audiences:
            - "my-audience"

相同属性适用于 Servlet 和 Reactive 应用程序。或者,可以为 Servlet 应用程序定义自己的 JwtDecoder bean 或为 Reactive 应用程序定义 ReactiveJwtDecoder bean。

在使用不透明令牌而不是 JWT 的情况下,可以配置以下属性来验证通过检查令牌:

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

同样,相同属性适用于 Servlet 和 Reactive 应用程序。或者,可以为 Servlet 应用程序定义自己的 OpaqueTokenIntrospector bean 或为 Reactive 应用程序定义 ReactiveOpaqueTokenIntrospector bean。

Authorization Server

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

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

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
          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 特有的自动配置:

  • RegisteredClientRepository

  • AuthorizationServerSettings

  • SecurityFilterChain

  • com.nimbusds.jose.jwk.source.JWKSource<com.nimbusds.jose.proc.SecurityContext>

  • JwtDecoder

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

可以在 {url-spring-authorization-server-docs}/getting-started.html[{url-spring-authorization-server-docs}[Spring Authorization Server 参考指南]] 的 [入门] 章节中找到更多信息。

SAML 2.0

Relying Party

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

依靠方注册表示身份提供程序 (IDP) 与服务提供程序 (SP) 之间的配对配置。可以在 spring.security.saml2.relyingparty 前缀下注册多个依靠方,如以下示例所示:

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