Как защитить ваше приложение Spring с помощью Spring Security

36
компьютеры и технологии 9.webp.webp

Последнее обновление 24.08.2023 — Василий Иванов

Платформа Spring Security защищает ваше приложение посредством аутентификации и авторизации. В состоянии по умолчанию Spring Security гарантирует, что каждый путь (или страница) HTTP-запроса в вашем приложении требует аутентификации одного глобального пользователя.

Эта структура также чрезвычайно гибкая. Это позволяет вам создавать индивидуальные правила безопасности для каждого пути HTTP-запроса в вашем приложении, а также для разных пользователей. Таким образом, вы можете снять ограничение безопасности на страницах, не требующих авторизации пользователя (например, на домашней странице). И установите роли и полномочия конкретных типов пользователей.

Добавление Spring Security в ваше приложение

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

По теме:  Как исправить код ошибки Microsoft Store 0xC002001B

Если вы выбрали один из вариантов проекта Gradle, то файлом зависимостей будет build.gradle. Однако если вы выбрали Maven, то это файл pom.xml.

Ваш файл build.gradle должен содержать следующую зависимость:

 dependencies {
      implementation 'org.springframework.boot:spring-boot-starter-security'
}

Хотя ваш файл pom.xml должен содержать следующую зависимость:

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

Пример приложения, использованный в статье, доступен в этом репозитории GitHub и может использоваться бесплатно по лицензии MIT.

Использование Spring Security

Как только вы добавите зависимость Spring Security в свое приложение, вы сразу же сможете начать использовать платформу. Просто запустите свое приложение, а затем перейдите на домашнюю страницу Spring Boot (или любую страницу вашего приложения). Пример приложения использует следующий начальный контроллер для управления запросом localhost:8080 Spring Boot по умолчанию:

 package com.springSecurityDemo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WebController {
   
     @GetMapping("https://www.makeuseof.com/")
      public String home() {
           return "Welcome!";
      }
}

Выполнение вашего приложения после добавления приведенного выше класса одного контроллера создает следующее начальное представление:

Вы заметите, что он автоматически направляет вас на страницу localhost:8080/login, и делает это до того, как вы сможете получить доступ к любой другой странице приложения. На этом этапе вам нужно будет указать имя пользователя по умолчанию (то есть пользователя) и автоматически сгенерированный пароль (который вы найдете в консоли). Консоль сгенерирует строку, подобную следующей:

 Using generated security password: c4070465-4c65-4e72-8c3f-3800e631ba81 

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

Настройка Spring Security

Чтобы настроить безопасность вашего приложения, вам необходимо переопределить конфигурацию Spring Security по умолчанию. Но перед этим (при условии, что у вас уже есть Spring Web) вам понадобится несколько других зависимостей для этого примера приложения:

  • Весенние данные JPA
  • MySQL JDBC-драйвер
  • Тимелиф
  • Ломбок

Платформа Thymeleaf будет генерировать разные представления. Lombok поможет сократить объем кода в ваших объектных классах. Библиотека JPA и драйвер MySQL позволят вам использовать базу данных MySQL с приложением, но у вас есть возможность использовать любую удобную вам базу данных. Использование базы данных означает настройку файла application.properties в файле ресурсов.

 spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/spring_security
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update

Приведенный выше код конфигурации позволяет вам подключиться к локальной базе данных MySQL под названием Spring_security с именем пользователя root и паролем (1234). Вам потребуется обновить эти данные, чтобы они соответствовали имени вашей базы данных и учетным данным.

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

  • Домашняя страница
  • Страница регистрации
  • Страница авторизации
  • Страница выхода из системы
  • Страница пользователя
  • Страница ошибки

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

Класс контроллера регистрации

Пакет контроллера будет содержать классы, обрабатывающие HTTP-запросы. В зависимости от функции страницы вы обычно можете сгруппировать каждый HTTP-запрос в один класс контроллера, как в случае с классом WebController. Однако представление регистрации имеет более уникальные функции, поэтому оно может иметь приватный класс контроллера:

 @Controller
@RequestMapping("/register")
public class RegistrationController {
       private UserRepository userRepo;
       private PasswordEncoder passwordEncoder;
       
       public RegistrationController( UserRepository userRepo, PasswordEncoder passwordEncoder) {
             this.userRepo = userRepo;
             this.passwordEncoder = passwordEncoder;
       }
       @GetMapping
       public String registerForm() {
             return "registration";
       }
       @PostMapping
       public String processRegistration(RegistrationForm form) {
             userRepo.save(form.toUser(passwordEncoder));
             return "redirect:/login";
       }
}

Класс RegistrationController — это шлюз к аспекту безопасности вашего приложения. Аннотация @RequestMapping указывает тип запроса, который будет обрабатывать этот контроллер (запросы к localhost:8080/register).

Аннотация @GetMapping просто указывает, что если приложение получает запрос на /register, метод RegistrationForm() должен обработать этот запрос, вернув представление регистрации.

После того, как посетитель нажимает кнопку регистрации, в игру вступает аннотация @PostMapping. МетодprocessRegistration() позволяет публиковать пользовательские данные, полученные из класса RegistrationForm, в базу данных, используя класс UserRepository. Но прежде чем сохранить эти данные, методprocessRegistration() шифрует пароль пользователя с помощью интерфейса Spring PasswordEncoder.

Создание новых конфигураций безопасности

Начиная с Spring 3.1, разработчики теперь могут создавать конфигурации Spring Security с использованием Java, что означает классы вместо XML. Главное, что требуется для этих классов конфигурации, — это аннотация @Configuration.

 @Configuration
public class SecurityConfiguration {
}

Аннотация @Configuration указывает, что указанный выше класс является классом конфигурации. Эти классы предоставляют bean-компоненты для контекста приложения Spring, который представляет собой контейнер, который Spring использует для создания и управления различными компонентами (или bean-компонентами) приложения. Первым компонентом в классе SecurityConfiguration является компонент пароляEncoder.

 @Bean
public PasswordEncoder passwordEncoder() {
 return new BCryptPasswordEncoder();
}

Класс RegistrationController использует bean-компонент пароляEncoder для кодирования новых паролей перед их сохранением в базе данных. Еще один важный компонент, который вам необходимо добавить в класс SecurityConfiguration, — это компонент userDetailsService.

 @Bean
public UserDetailsService userDetailsService(UserRepository userRepo) {
 return username -> {
   Customer customer = userRepo.findByUsername(username);
     if (customer != null)
           return customer;
     throw new UsernameNotFoundException("Customer '" + username + "' not found");
 };
}

Компонент userDetailsService использует интерфейс UserDetailsService Spring Security для получения имени пользователя и пароля пользователя для аутентификации во время сеанса входа клиента в систему. Таким образом, как только клиент нажимает кнопку входа в систему в представлении входа в систему, bean-компонент userDetailsService приходит в движение.

Через UserRepository bean-компонент userDetailsService получает доступ ко всем существующим клиентам в базе данных. Затем этот интерфейс использует UserRepository для поиска пользователя с совпадающим именем пользователя и паролем, а затем возвращает все атрибуты этого клиента в виде объекта.

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

Цепочка фильтров

Интерфейс SecurityFilterChain Spring Security — это полезный интерфейс прикладного программирования (API), который играет важную роль в конфигурации Spring Security. Этот интерфейс работает с классом HttpSecurity Spring Security для создания цепочки фильтров для определенных HTTP-запросов.

 @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  http
  .authorizeHttpRequests((authorize) -> authorize
              .requestMatchers("/user").hasAuthority("USER").anyRequest().permitAll())
  .formLogin(formLogin -> formLogin
              .loginPage("/login").defaultSuccessUrl("/user", true))
  .logout(logout -> logout.logoutSuccessUrl("/logout"));
 return http.build();
}

Компонент filterChain, приведенный выше, использует API SecurityFilterChain для выполнения нескольких задач. Во-первых, он использует класс HttpSecurity, чтобы указать, что только пользователи с ролью USER могут получить доступ к localhost:8080/user. И пользователь получает эту роль после регистрации благодаря методу getAuthorities(), который реализует каждый новый объект клиента.

 @Override
public Collection<? extends GrantedAuthority> getAuthorities() {
 return Arrays.asList(new SimpleGrantedAuthority("USER"));
}

Цепочка фильтров обеспечивает неаутентифицированный доступ ко всем остальным URL-адресам в приложении. Компонент filterChain также использует методы formLogin() и logout() объекта класса HttpSecurity.

Эти методы позволяют автоматически перенаправлять пользователя на определенные страницы после выполнения им задачи. Таким образом, пользователь, который вводит правильные учетные данные и нажимает кнопку входа на странице /login, будет автоматически перенаправлен на страницу /user.

Наконец, bean-компонент filterChain создает и возвращает цепочку фильтров, которая позволяет авторизованным пользователям получать доступ к приложению. Все три компонента класса SecurityConfiguration работают вместе, обеспечивая безопасность вашего приложения.

Однако компонент filterChain играет более важную роль, определяя уровень авторизации для каждого HTTP-запроса. Когда вы начнете добавлять больше страниц в свое приложение, вы можете использовать bean-компонент filterChain для установки уровня их безопасности.

Основное преимущество Spring Security

Spring Security дает вам полный контроль не только над тем, кто имеет доступ к вашему приложению, но и над типом доступа, который может иметь пользователь (с помощью функции ролей пользователей). Контроль доступа является одним из наиболее важных аспектов любого приложения. Предоставление обычным пользователям нефильтрованного доступа к вашему приложению из-за ограниченных барьеров контроля доступа может оказаться дорогостоящей ошибкой.