Перейти к основному содержимому

Автоматическая настройка безопасности Spring Boot

· 8 мин. чтения

Упражнение: Сложение двух чисел

Даны два неотрицательный целых числа в виде непустых связных списков. Их цифры хранятся в обратном порядке. И каждый елемент списка содержить ровно одну цифру. Сложите эти два числа и верните сумму в виде связного списка ...

ANDROMEDA

1. Обзор

В этом руководстве мы рассмотрим самоуверенный подход Spring Boot к безопасности.

Проще говоря, мы собираемся сосредоточиться на конфигурации безопасности по умолчанию и на том, как мы можем отключить или настроить ее, если нам это нужно.

2. Настройка безопасности по умолчанию

Чтобы добавить безопасность в наше приложение Spring Boot, нам нужно добавить стартовую зависимость безопасности :

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Это также будет включать класс SecurityAutoConfiguration , содержащий начальную/стандартную конфигурацию безопасности.

Обратите внимание, что мы не указали здесь версию, предполагая, что проект уже использует Boot в качестве родителя.

По умолчанию для приложения включена аутентификация. Кроме того, согласование содержимого используется для определения того, следует ли использовать базовый или formLogin.

Есть некоторые предопределенные свойства:

spring.security.user.name
spring.security.user.password

Если мы не настроим пароль с помощью предопределенного свойства spring.security.user.password и не запустим приложение, пароль по умолчанию будет сгенерирован случайным образом и напечатан в журнале консоли:

Using default security password: c8be15de-4488-4490-9dc6-fab3f91435c6

Дополнительные значения по умолчанию см. в разделе свойств безопасности на справочной странице Spring Boot Common Application Properties .

3. Отключение автоконфигурации

Чтобы отказаться от автоматической настройки безопасности и добавить собственную конфигурацию, нам нужно исключить класс SecurityAutoConfiguration .

Мы можем сделать это с помощью простого исключения:

@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class SpringBootSecurityApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootSecurityApplication.class, args);
}
}

Или мы можем добавить некоторую конфигурацию в файл application.properties :

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration

Однако есть и некоторые частные случаи, когда этой настройки недостаточно.

Например, почти каждое приложение Spring Boot запускается с Actuator в пути к классам. Это вызывает проблемы, потому что другой класс автоконфигурации нуждается в том, который мы только что исключили. Таким образом, приложение не запустится.

Чтобы решить эту проблему, нам нужно исключить этот класс; и, что касается ситуации с приводом, нам также необходимо исключить ManagementWebSecurityAutoConfiguration .

3.1. Отключение или превышение автоматической настройки безопасности

Есть существенная разница между отключением автоконфигурации и ее превышением.

Его отключение аналогично добавлению зависимости Spring Security и всей настройки с нуля. Это может быть полезно в нескольких случаях:

  1. Интеграция безопасности приложений с настраиваемым поставщиком безопасности
  2. Миграция устаревшего приложения Spring с уже существующей настройкой безопасности — на Spring Boot

Но в большинстве случаев нам не нужно полностью отключать автоматическую настройку безопасности.

Это связано с тем, что Spring Boot настроен на то, чтобы разрешить превышение автоматически настроенной безопасности путем добавления наших новых/настраиваемых классов конфигурации. Обычно это проще, так как мы просто настраиваем существующую настройку безопасности для удовлетворения наших потребностей.

4. Настройка безопасности Spring Boot

Если мы выбрали путь отключения автоматической настройки безопасности, нам, естественно, необходимо предоставить собственную конфигурацию.

Как мы уже обсуждали ранее, это конфигурация безопасности по умолчанию. Затем мы настраиваем его, изменяя файл свойств.

Например, мы можем переопределить пароль по умолчанию, добавив свой собственный:

spring.security.user.password=password

Если нам нужна более гибкая конфигурация, например, с несколькими пользователями и ролями, нам нужно использовать полный класс @Configuration :

@Configuration
@EnableWebSecurity
public class BasicConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth
.inMemoryAuthentication()
.withUser("user")
.password(encoder.encode("password"))
.roles("USER")
.and()
.withUser("admin")
.password(encoder.encode("admin"))
.roles("USER", "ADMIN");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
}

Аннотация @EnableWebSecurity имеет решающее значение, если мы отключим конфигурацию безопасности по умолчанию.

Приложение не запустится, если оно отсутствует. Таким образом, аннотация необязательна только в том случае, если мы просто переопределяем поведение по умолчанию с помощью WebSecurityConfigurerAdapter .

Также обратите внимание, что нам нужно использовать PasswordEncoder для установки паролей при использовании Spring Boot 2. Дополнительные сведения см. в нашем руководстве по кодировщику паролей по умолчанию в Spring Security 5 .

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

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
public class BasicConfigurationIntegrationTest {

TestRestTemplate restTemplate;
URL base;
@LocalServerPort int port;

@Before
public void setUp() throws MalformedURLException {
restTemplate = new TestRestTemplate("user", "password");
base = new URL("http://localhost:" + port);
}

@Test
public void whenLoggedUserRequestsHomePage_ThenSuccess()
throws IllegalStateException, IOException {
ResponseEntity<String> response =
restTemplate.getForEntity(base.toString(), String.class);

assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response.getBody().contains("ForEach"));
}

@Test
public void whenUserWithWrongCredentials_thenUnauthorizedPage()
throws Exception {

restTemplate = new TestRestTemplate("user", "wrongpassword");
ResponseEntity<String> response =
restTemplate.getForEntity(base.toString(), String.class);

assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
assertTrue(response.getBody().contains("Unauthorized"));
}
}

Spring Security на самом деле стоит за Spring Boot Security, поэтому любая конфигурация безопасности, которая может быть выполнена с помощью этого, или любая интеграция, которую он поддерживает, также может быть реализована в Spring Boot.

5. Автоконфигурация Spring Boot OAuth2 (с использованием устаревшего стека)

Spring Boot имеет специальную поддержку автоматической настройки для OAuth2.

Поддержка Spring Security OAuth , поставляемая с Spring Boot 1.x, была удалена в более поздних загрузочных версиях вместо первоклассной поддержки OAuth, поставляемой в комплекте с Spring Security 5 . Мы увидим, как это использовать в следующем разделе.

Для устаревшего стека (с использованием Spring Security OAuth) нам сначала нужно добавить зависимость Maven, чтобы начать настройку нашего приложения:

<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>

Эта зависимость включает в себя набор классов, способных запускать механизм автоматической настройки, определенный в классе OAuth2AutoConfiguration .

Теперь у нас есть несколько вариантов продолжения в зависимости от области нашего приложения.

5.1. Автоматическая настройка сервера авторизации OAuth2

Если мы хотим, чтобы наше приложение было поставщиком OAuth2, мы можем использовать @EnableAuthorizationServer .

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

Using default security password: a81cb256-f243-40c0-a585-81ce1b952a98
security.oauth2.client.client-id = 39d2835b-1f87-4a77-9798-e2975f36972e
security.oauth2.client.client-secret = f1463f8b-0791-46fe-9269-521b86c55b71

Эти учетные данные можно использовать для получения токена доступа:

curl -X POST -u 39d2835b-1f87-4a77-9798-e2975f36972e:f1463f8b-0791-46fe-9269-521b86c55b71 \
-d grant_type=client_credentials
-d username=user
-d password=a81cb256-f243-40c0-a585-81ce1b952a98 \
-d scope=write http://localhost:8080/oauth/token

В другой нашей статье содержится дополнительная информация по этому вопросу.

5.2. Другие параметры автоконфигурации Spring Boot OAuth2

Есть и другие варианты использования Spring Boot OAuth2:

  1. Сервер ресурсов@EnableResourceServer
  2. Клиентское приложение@EnableOAuth2Sso или @EnableOAuth2Client

Если нам нужно, чтобы наше приложение относилось к одному из этих типов, нам просто нужно добавить некоторую конфигурацию в свойства приложения, как подробно описано по ссылкам.

Все специфические свойства OAuth2 можно найти в Spring Boot Common Application Properties .

6. Автоконфигурация Spring Boot OAuth2 (с использованием нового стека)

Чтобы использовать новый стек, нам нужно добавить зависимости в зависимости от того, что мы хотим настроить — сервер авторизации, сервер ресурсов или клиентское приложение.

Давайте посмотрим на них один за другим.

6.1. Поддержка сервера авторизации OAuth2

Как мы видели, стек Spring Security OAuth предлагал возможность настроить сервер авторизации в качестве приложения Spring. Но проект устарел, и Spring на данный момент не поддерживает собственный сервер авторизации. Вместо этого рекомендуется использовать существующих хорошо зарекомендовавших себя провайдеров, таких как Okta, Keycloak и ForgeRock.

Однако Spring Boot упрощает настройку таких поставщиков. В качестве примера конфигурации Keycloak мы можем обратиться либо к A Quick Guide to Using Keycloak With Spring Boot , либо к Keycloak Embedded in a Spring Boot Application .

6.2. Поддержка сервера ресурсов OAuth2

Чтобы включить поддержку сервера ресурсов, нам нужно добавить эту зависимость:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

Для получения информации о последней версии перейдите на Maven Central .

Кроме того, в нашей конфигурации безопасности нам нужно включить DSL oauth2ResourceServer() :

@Configuration
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.oauth2ResourceServer(oauth2 -> oauth2.jwt());
...
}
}

Наш сервер ресурсов OAuth 2.0 с Spring Security 5 дает подробное представление об этой теме.

6.3. Поддержка клиентов OAuth2

Подобно тому, как мы настроили сервер ресурсов, клиентское приложение также нуждается в собственных зависимостях и DSL.

Вот конкретная зависимость для поддержки клиента OAuth2:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

Последнюю версию можно найти на Maven Central .

Spring Security 5 также обеспечивает первоклассную поддержку входа в систему через DSL oath2Login() .

Подробнее о поддержке единого входа в новом стеке читайте в нашей статье Simple Single Sign-On With Spring Security OAuth2 .

7. Безопасность Spring Boot 2 против безопасности Spring Boot 1

По сравнению с Spring Boot 1, Spring Boot 2 значительно упростил автоматическую настройку.

В Spring Boot 2, если нам нужна собственная конфигурация безопасности, мы можем просто добавить собственный WebSecurityConfigurerAdapter . Это отключит автоматическую настройку по умолчанию и включит нашу пользовательскую конфигурацию безопасности.

Spring Boot 2 также использует большинство значений Spring Security по умолчанию. Таким образом, некоторые из конечных точек, которые по умолчанию не были защищены в Spring Boot 1, теперь защищены по умолчанию.

Эти конечные точки включают статические ресурсы, такие как /css/, /js/, /images/, /webjars/, /**/favicon.ico и конечную точку ошибки. Если нам нужно разрешить неаутентифицированный доступ к этим конечным точкам, мы можем явно настроить это.

Чтобы упростить конфигурацию, связанную с безопасностью, Spring Boot 2 удалил эти свойства Spring Boot 1 :

security.basic.authorize-mode
security.basic.enabled
security.basic.path
security.basic.realm
security.enable-csrf
security.headers.cache
security.headers.content-security-policy
security.headers.content-security-policy-mode
security.headers.content-type
security.headers.frame
security.headers.hsts
security.headers.xss
security.ignored
security.require-ssl
security.sessions

8. Заключение

В этой статье мы сосредоточились на конфигурации безопасности по умолчанию, предоставляемой Spring Boot. Мы увидели, как можно отключить или переопределить механизм автоматической настройки безопасности. Затем мы рассмотрели, как можно применить новую конфигурацию безопасности.

Исходный код для OAuth2 можно найти в нашем репозитории OAuth2 GitHub для старого и нового стека . Остальной код можно найти на GitHub .