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

Безопасность и авторизация

Механизм аутентификации

Система использует JWT (JSON Web Token) с библиотекой JJWT. Сессии — stateless: сервер не хранит состояние сессии, каждый запрос содержит токен.

Жизненный цикл токена

1. POST /api/v1/auth/login
Body: { email, password }

→ AuthServiceImpl.authenticate()
→ AuthenticationManager.authenticate() # проверка пароля (BCrypt)
→ JwtService.generateToken(UserDetails) # создание JWT

Response: { token: "eyJ...", user: { id, name, email, role } }

2. Клиент сохраняет токен:
localStorage.setItem('dm_shop_token', token)

3. Axios Interceptor (src/lib/api.ts):
config.headers.Authorization = `Bearer ${token}`

4. JwtAuthFilter (Spring Security Filter Chain):
→ Читает заголовок Authorization
→ JwtService.extractUsername(token)
→ UserDetailsService.loadUserByUsername(email)
→ SecurityContextHolder.setAuthentication(authToken)

Параметры JWT

ПараметрЗначениеПеременная окружения
Алгоритм подписиHMAC-SHA256
Секретный ключ64-байтный hexJWT_SECRET
Время жизни24 часа (86 400 000 мс)JWT_EXPIRATION_MS
Хранение на клиентеlocalStorage

Роли пользователей

Три роли определены в UserRole:

РольОписание
USERЗарегистрированный покупатель: просмотр, оформление заказов
MANAGERМенеджер: обработка заказов, обращений
ADMINПолный доступ ко всему

Правила доступа

Публичные эндпоинты (без токена)

POST /api/v1/auth/register
POST /api/v1/auth/login
GET /api/v1/products/**
GET /api/v1/categories/**
GET /api/v1/brands
GET /api/v1/reviews/active
GET /api/v1/banner-blocks/active
GET /api/v1/feature-items/active
GET /api/v1/config/public
GET /api/v1/images/{id}
POST /api/v1/cart/validate
POST /api/v1/contacts
GET /swagger-ui/**
GET /v3/api-docs/**

Только авторизованные (роль USER+)

POST /api/v1/orders
GET /api/v1/orders/**
PUT /api/v1/auth/profile
PUT /api/v1/auth/change-password

Только ADMIN / MANAGER

/api/v1/admin/**
POST /api/v1/reviews
PUT /api/v1/reviews/**
DELETE /api/v1/reviews/**
POST /api/v1/images
PUT /api/v1/images/**
DELETE /api/v1/images/**
/api/v1/banner-blocks (POST/PUT/DELETE)
/api/v1/feature-items (POST/PUT/DELETE)
/api/v1/config/**

Примечание: На момент текущей версии некоторые эндпоинты настроены через permitAll() в SecurityConfig — механизм проверки токена работает, но принудительная авторизация ещё не везде активна. Строгий контроль планируется.

Конфигурация Spring Security

// SecurityConfig.java — ключевые настройки
http
.csrf(AbstractHttpConfigurer::disable) // REST API — CSRF не нужен
.sessionManagement(s -> s.sessionCreationPolicy(STATELESS))
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/**").permitAll()
.requestMatchers("/api/v1/admin/**").hasAnyRole("ADMIN", "MANAGER")
// ...
.anyRequest().permitAll() // временно
);

Хеширование паролей

Используется BCryptPasswordEncoder (стандартный Spring Security). Пароли в базе данных хранятся только в виде bcrypt-хешей, не в открытом виде.

CORS

Настраивается в WebConfig через свойство cors.allowed-origins:

# application-local.yaml
cors:
allowed-origins: http://localhost:3000

# Production
cors:
allowed-origins: https://shop.example.com

Разрешены методы: GET, POST, PUT, PATCH, DELETE, OPTIONS.
Разрешены все заголовки (*).
Разрешены credentials.

Регистрация и профиль

POST /api/v1/auth/register
Body: { name, email, password }
→ Проверка уникальности email (DuplicateEmailException если занят)
→ BCrypt.encode(password)
→ UserEntity.role = USER
→ Возвращает JWT токен сразу

PUT /api/v1/auth/profile
Body: { name, phone }
→ Требует токен (текущий пользователь)

PUT /api/v1/auth/change-password
Body: { currentPassword, newPassword }
→ Проверяет currentPassword через BCrypt.matches()