Если Spring Security находится в classpath, то веб-приложения по умолчанию защищены. Spring Boot полагается на стратегию согласования содержимого Spring Security, чтобы определять, использовать ли httpBasic или formLogin. Чтобы внедрить средства безопасности на уровне методов в веб-приложение, также можно добавить аннотацию @EnableGlobalMethodSecurity с желаемыми настройками.

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.name и spring.security.user.password.

Основные функции, которые вам доступны по умолчанию в веб-приложении, следующие:

  • Бин UserDetailsService (или ReactiveUserDetailsService в случае приложения на WebFlux) с хранилищем в памяти и одним пользователем со сгенерированным паролем (свойства пользователя см. в SecurityProperties.User).

  • Вход в систему с помощью форм или защита с помощью HTTP Basic (в зависимости от заголовка Accept в запросе) для всего приложения (включая конечные точки актуатора, если актуатор находится в classpath).

  • DefaultAuthenticationEventPublisher для публикации событий аутентификации.

Вы можете передать другой AuthenticationEventPublisher, добавив для него бин.

Средства безопасности для MVC

Конфигурация средств безопасности по умолчанию реализована в SecurityAutoConfiguration и UserDetailsServiceAutoConfiguration. SecurityAutoConfiguration импортирует SpringBootWebSecurityConfiguration для обеспечения веб-безопасности, а UserDetailsServiceAutoConfiguration конфигурирует аутентификацию, что также актуально для не связанных с веб приложений. Чтобы полностью отключить стандартную конфигурацию средств безопасности веб-приложения или объединить несколько компонентов Spring Security, таких как клиент и сервер ресурсов OAuth2, добавьте бин типа SecurityFilterChain (при этом конфигурация UserDetailsService или средства безопасности для Actuator не будут отключены).

Чтобы, помимо прочего, отключить конфигурацию UserDetailsService, можно добавить бин типа UserDetailsService, AuthenticationProvider или AuthenticationManager.

Правила доступа можно переопределять путем добавления пользовательского бина SecurityFilterChain или WebSecurityConfigurerAdapter. Spring Boot предусматривает вспомогательные методы, которые можно использовать для переопределения правил доступа для конечных точек актуаторов и статических ресурсов. EndpointRequest можно использовать для создания RequestMatcher, который основывается на свойстве management.endpoints.web.base-path. PathRequest можно использовать, чтобы создать RequestMatcher для ресурсов, находящихся в часто используемых местоположениях.

Безопасность в WebFlux

Подобно приложениям Spring MVC, можно защитить свои приложения WebFlux, добавив зависимость spring-boot-starter-security. Конфигурация средств безопасности по умолчанию реализована в ReactiveSecurityAutoConfiguration и UserDetailsServiceAutoConfiguration. ReactiveSecurityAutoConfiguration импортирует WebFluxSecurityConfiguration для обеспечения веб-безопасности, а UserDetailsServiceAutoConfiguration конфигурирует аутентификацию, что также актуально для приложений, не связанных с веб. Чтобы полностью отключить стандартную конфигурацию средств безопасности веб-приложения, можно добавить бин типа WebFilterChainProxy (при этом конфигурация UserDetailsService или средства безопасности для Actuator не отключаются).

Чтобы также отключить конфигурацию UserDetailsService, можно добавить бин типа ReactiveUserDetailsService или ReactiveAuthenticationManager.

Правила доступа и использование нескольких компонентов Spring Security, таких как клиент и сервер ресурсов OAuth 2 можно настроить путем добавления кастомного бина SecurityWebFilterChain. Spring Boot предусматривает вспомогательные методы, которые можно использовать для переопределения правил доступа для конечных точек актуаторов и статических ресурсов. EndpointRequest можно использовать для создания ServerWebExchangeMatcher, который основан на свойстве management.endpoints.web.base-path.

PathRequest можно использовать, чтобы создать ServerWebExchangeMatcher для ресурсов, находящихся в часто используемых местоположениях.

Например, можно настроить конфигурацию средств безопасности, добавив что-то вроде:

Java
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();
    }
}
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
@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()
        return http.build()
    }
}

OAuth2

OAuth2 – это широко используемая система авторизации, которая поддерживается Spring.

Клиент

Если в вашем classpath есть spring-security-oauth2-client, то можно воспользоваться некоторыми возможностями автоконфигурации для установки клиентов OAuth2/Open ID Connect. Эта конфигурация использует свойства из OAuth2ClientProperties. Эти же свойства применимы как к сервлетам, так и к реактивным приложениям.

Вы можете зарегистрировать несколько клиентов и поставщиков OAuth2 под префиксом spring.security.oauth2.client, как показано в следующем примере:

Properties
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=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=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=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=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/oauth/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server/oauth/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server/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/token_keys
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name
Yaml
spring:
  security:
    oauth2:
      client:
        registration:
          my-client-1:
            client-id: "abcd"
            client-secret: "password"
            client-name: "Client for user scope"
            provider: "my-oauth-provider"
            scope: "user"
            redirect-uri: "https://my-redirect-uri.com"
            client-authentication-method: "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: "https://my-redirect-uri.com"
            client-authentication-method: "basic"
            authorization-grant-type: "authorization_code"
        provider:
          my-oauth-provider:
            authorization-uri: "https://my-auth-server/oauth/authorize"
            token-uri: "https://my-auth-server/oauth/token"
            user-info-uri: "https://my-auth-server/userinfo"
            user-info-authentication-method: "header"
            jwk-set-uri: "https://my-auth-server/token_keys"
            user-name-attribute: "name"

Для поставщиков OpenID Connect, которые поддерживают обнаружение OpenID Connect, конфигурацию можно еще больше упростить. Поставщик должен быть сконфигурирован с использованием issuer-uri, являющегося URI-идентификатором, который добавляет утверждение о том, что данный URI-идентификатор является идентификатором издателя. Например, если передаваемый issuer-uri – "https://example.com", то запрос OpenID Provider Configuration Request будет сделан на "https://example.com/.well-known/openid-configuration". Ожидается, что результатом будет ответ OpenID Provider Configuration Response. В следующем примере показано, как поставщик OpenID Connect можно сконфигурировать при помощи issuer-uri:

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

По умолчанию OAuth2LoginAuthenticationFilter в Spring Security обрабатывает только URL-адреса, соответствующие /login/oauth2/code/*. Если необходимо настроить redirect-uri на использование другого шаблона, то требуется создать конфигурацию для обработки этого шаблона. Например, для приложений сервлетов можно добавить собственную SecurityFilterChain, которая будет похожа на следующую:

Java
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;
@Configuration(proxyBeanMethods = false)
public class MyOAuthClientConfiguration {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
        http.oauth2Login((login) -> login.redirectionEndpoint().baseUri("custom-callback"));
        return http.build();
    }
}
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.web.SecurityFilterChain
@Configuration(proxyBeanMethods = false)
class MyOAuthClientConfiguration {
    @Bean
    fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
        http.authorizeRequests().anyRequest().authenticated()
        http.oauth2Login().redirectionEndpoint().baseUri("custom-callback")
        return http.build()
    }
}
Spring Boot автоматически конфигурирует InMemoryOAuth2AuthorizedClientService, который используется Spring Security для управления процедурами регистрации клиентов. InMemoryOAuth2AuthorizedClientService имеет ограниченные возможности, поэтому мы рекомендуем использовать его только в окружениях разработки. В производственных окружениях используйте JdbcOAuth2AuthorizedClientService или создайте собственную реализацию OAuth2AuthorizedClientService.

Регистрация клиентов OAuth2 для общих поставщиков

Для распространенных поставщиков OAuth2 и OpenID, включая Google, Github, Facebook и Okta, мы предусматриваем набор поставщиков по умолчанию (google, github, facebook и okta, соответственно).

Если не требуется настраивать этих поставщиков, то можете установить атрибут provider для того, для которого требуется вывести значения по умолчанию. Кроме того, если ключ для регистрации клиента совпадёт с поддерживаемым по умолчанию поставщиком, Spring Boot определит и его.

Иными словами, две конфигурации в следующем примере используют поставщика Google:

Properties
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
Yaml
spring:
  security:
    oauth2:
      client:
        registration:
          my-client:
            client-id: "abcd"
            client-secret: "password"
            provider: "google"
          google:
            client-id: "abcd"
            client-secret: "password"

Сервер ресурсов

Если в вашем classpath есть spring-security-oauth2-resource-server, Spring Boot может установить сервер ресурсов OAuth2. Для JWT-конфигурации необходимо указать JWK Set URI или OIDC Issuer URI, как показано в следующих примерах:

Properties
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
Yaml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: "https://example.com/oauth2/default/v1/keys"
Properties
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
Yaml
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.

Те же свойства применимы как для сервлетных, так и для реактивных приложений.

Кроме того, можно определить свой собственный бин JwtDecoder для сервлетных приложений или ReactiveJwtDecoder для реактивных приложений.

В случаях, если вместо JWT используются непрозрачные токены, можно сконфигурировать следующие свойства для валидации токенов посредством интроспекции:

Properties
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
Yaml
spring:
  security:
    oauth2:
      resourceserver:
        opaquetoken:
          introspection-uri: "https://example.com/check-token"
          client-id: "my-client-id"
          client-secret: "my-client-secret"

Опять же, одни и те же свойства применимы как для сервлетных, так и для реактивных приложений.

В качестве альтернативы можно определить свой собственный бин OpaqueTokenIntrospector для сервлетных приложений или ReactiveOpaqueTokenIntrospector для реактивных приложений.

Сервер авторизации

В настоящее время Spring Security не предусматривает поддержку для реализации сервера авторизации OAuth 2.0. Однако эта функциональность доступна из проекта Spring Security OAuth, который со временем будет полностью вытеснен Spring Security. До тех пор можно использовать модуль spring-security-oauth2-autoconfigure для простой настройки сервера авторизации OAuth 2.0; см. документацию для ознакомления с инструкциями.