Java for Beginner
695 subscribers
603 photos
165 videos
12 files
932 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Использование базы данных для хранения пользователей в Spring Security

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

1. Общая архитектура

Когда Spring Security использует базу данных для аутентификации, основные элементы выглядят следующим образом:
База данных: Хранит таблицы пользователей и ролей.
UserDetailsService: Загрузчик пользователей, который извлекает данные из базы данных.
PasswordEncoder: Обеспечивает хэширование паролей.
AuthenticationManager: Выполняет процесс аутентификации.
Роли и привилегии: Хранятся в базе для управления авторизацией.


2. Шаги по реализации

2.1 Настройка базы данных
Создайте базу данных и добавьте необходимые таблицы для хранения пользователей и их ролей. Рассмотрим пример на основе реляционной базы данных.

Пример SQL-схемы:
-- Таблица пользователей
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
enabled BOOLEAN NOT NULL
);

-- Таблица ролей
CREATE TABLE roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE
);

-- Таблица связи пользователей и ролей
CREATE TABLE user_roles (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id)
);


Пример данных:
INSERT INTO users (username, password, enabled) VALUES 
('admin', '$2a$10$7a6yXl4bKh7QvXuUIhEY2eP2d6P5M6NmrkObWbxODeEM.gSUTZlVu', true), -- пароль: admin
('user', '$2a$10$w8y4/gM3/uF9Rf/5S1OejX.6M4KZt7eEPY2OnB9oRxCSU8Y4.jK8u', true); -- пароль: user

INSERT INTO roles (name) VALUES ('ROLE_ADMIN'), ('ROLE_USER');

INSERT INTO user_roles (user_id, role_id) VALUES
(1, 1), -- admin имеет роль ROLE_ADMIN
(2, 2); -- user имеет роль ROLE_USER
Пароли были закодированы с использованием BCryptPasswordEncoder.


2.2 Настройка приложения
Подключение к базе данных

Настройте подключение к базе данных в файле application.properties (или application.yml):

application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/spring_security_db
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update


Зависимости
Добавьте зависимости для работы с базой данных и Spring Security:

Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>


Gradle:
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'mysql:mysql-connector-java'


#Java #Training #Spring #Security #Security_BD
👍1
2.3 Реализация UserDetailsService
Spring Security использует интерфейс UserDetailsService для загрузки пользователей из базы данных. Реализуем его в нашем приложении.
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collections;

@Service
public class CustomUserDetailsService implements UserDetailsService {

private final UserRepository userRepository;

public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity userEntity = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Пользователь не найден: " + username));

return User.builder()
.username(userEntity.getUsername())
.password(userEntity.getPassword())
.authorities(userEntity.getRoles().stream()
.map(role -> "ROLE_" + role.getName())
.toList())
.accountExpired(false)
.accountLocked(false)
.credentialsExpired(false)
.disabled(!userEntity.isEnabled())
.build();
}
}


2.4 Создание Репозиториев
Создадим репозитории для работы с таблицами пользователей и ролей.


UserRepository:
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<UserEntity, Long> {
Optional<UserEntity> findByUsername(String username);
}


RoleRepository:
import org.springframework.data.jpa.repository.JpaRepository;

public interface RoleRepository extends JpaRepository<RoleEntity, Long> {
}


2.5 Создание Сущностей
UserEntity:
import jakarta.persistence.*;
import java.util.Set;

@Entity
@Table(name = "users")
public class UserEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, unique = true)
private String username;

@Column(nullable = false)
private String password;

@Column(nullable = false)
private boolean enabled;

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<RoleEntity> roles;

// Геттеры и сеттеры
}


RoleEntity:
import jakarta.persistence.*;
import java.util.Set;

@Entity
@Table(name = "roles")
public class RoleEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, unique = true)
private String name;

@ManyToMany(mappedBy = "roles")
private Set<UserEntity> users;

// Геттеры и сеттеры
}


#Java #Training #Spring #Security #Security_BD
👍1
2.6 Настройка Конфигурации Безопасности
Настроим SecurityConfig для использования пользовательской реализации UserDetailsService.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

private final CustomUserDetailsService customUserDetailsService;

public SecurityConfig(CustomUserDetailsService customUserDetailsService) {
this.customUserDetailsService = customUserDetailsService;
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin()
.and()
.logout().permitAll();

return http.build();
}

@Bean
public AuthenticationManager authManager(HttpSecurity http, PasswordEncoder passwordEncoder)
throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder)
.and()
.build();
}

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


3. Тестирование

Теперь, когда настройка завершена:
Вы можете зарегистрировать новых пользователей, хэшировать их пароли с помощью BCryptPasswordEncoder и сохранять их в базу данных.
При попытке входа Spring
Security будет извлекать пользователя из базы данных через CustomUserDetailsService.

#Java #Training #Spring #Security #Security_BD
1👍1