Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Access Token: безопасность и аутентификация
Access Token — это цифровой токен (обычно JWT), который выдаётся клиенту после успешной аутентификации. Он используется для доступа к защищённым ресурсам API без повторной отправки пароля на каждый запрос.
Как работает Access Token
Процесс аутентификации и авторизации:
1. Клиент отправляет username/password
|
v
2. Сервер проверяет учётные данные
|
v
3. Сервер генерирует Access Token (+ Refresh Token)
|
v
4. Клиент отправляет Token в заголовке каждого запроса
|
v
5. Сервер проверяет валидность Token
|
v
6. Если Token валиден → доступ к ресурсу
Если Token истёк → используется Refresh Token
JWT (JSON Web Token) — самый популярный формат
// Access Token обычно это JWT, состоящий из 3 частей
// Header.Payload.Signature
// Пример JWT:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
// Декодированный payload:
// {
// "sub": "1234567890", // Subject (user ID)
// "name": "John Doe", // User name
// "iat": 1516239022, // Issued at (время создания)
// "exp": 1516242622 // Expiration (время истечения)
// }
Пример использования в Java с Spring Security
// 1. Генерация Access Token при логине
@Service
public class JwtTokenProvider {
private static final String SECRET = "your-secret-key";
private static final long EXPIRATION = 3600000; // 1 час
public String generateAccessToken(String username, List<String> roles) {
return Jwts.builder()
.setSubject(username)
.claim("roles", roles)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
}
public String validateAndGetUsername(String token) {
try {
Claims claims = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
} catch (JwtException | IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid token", e);
}
}
}
// 2. Login endpoint
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private JwtTokenProvider tokenProvider;
@Autowired
private AuthenticationManager authManager;
@PostMapping("/login")
public ResponseEntity<AuthResponse> login(@RequestBody LoginRequest request) {
// Проверяем username и password
Authentication auth = authManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.getUsername(),
request.getPassword()
)
);
UserDetails user = (UserDetails) auth.getPrincipal();
String accessToken = tokenProvider.generateAccessToken(
user.getUsername(),
user.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.toList()
);
return ResponseEntity.ok(new AuthResponse(accessToken));
}
}
// 3. Использование Token в защищённом endpoint
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/profile")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<UserProfile> getProfile(
@AuthenticationPrincipal UserDetails user
) {
// Token уже проверен Spring Security
return ResponseEntity.ok(userService.getProfile(user.getUsername()));
}
}
// 4. Клиент отправляет Token в каждом запросе
// Заголовок: Authorization: Bearer <access_token>
// GET /api/profile
// Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Жизненный цикл Token'а
// Access Token имеет ограниченное время жизни (обычно 15-60 минут)
// После истечения нужен Refresh Token для получения нового Access Token
@PostMapping("/refresh")
public ResponseEntity<AuthResponse> refreshToken(
@RequestBody RefreshTokenRequest request
) {
// Проверяем Refresh Token (обычно живёт дольше, 7-30 дней)
String username = tokenProvider.validateRefreshToken(request.getRefreshToken());
// Генерируем новый Access Token
String newAccessToken = tokenProvider.generateAccessToken(username, roles);
return ResponseEntity.ok(new AuthResponse(newAccessToken));
}
Безопасность Access Token
Чего НЕЛЬЗЯ делать:
// ❌ Хранить пароль в Token
Jwts.builder()
.claim("password", user.getPassword()) // ОПАСНО!
.build();
// ❌ Передавать Token в URL
GET /api/resource?token=eyJhbGc... // ОПАСНО, логируется в логах
// ❌ Хранить sensitive данные в Token
Jwts.builder()
.claim("creditCard", "4111-1111-1111-1111") // ОПАСНО!
.build();
// ❌ Использовать слабый SECRET
private static final String SECRET = "secret"; // Слишком короткий
Правильно:
// ✅ Хранить только user ID и минимум info
Jwts.builder()
.setSubject(user.getId()) // Только ID
.claim("roles", roles) // Роли
.build();
// ✅ Передавать Token в заголовке Authorization
// Authorization: Bearer <token>
// ✅ Использовать HTTPS для всех запросов
// ✅ Использовать strong SECRET (минимум 256 бит)
private static final String SECRET = "your-very-long-secret-key-with-minimum-256-bits-of-entropy";
// ✅ Хранить Access Token в памяти (не в localStorage в браузере)
// ✅ Хранить Refresh Token в secure HttpOnly Cookie
Access Token vs Refresh Token
Тип Token | Время жизни | Где хранить | Назначение
-----------+-------------+-------------+----------------------
Access | 15-60 мин | Память | Доступ к ресурсам
Refresh | 7-30 дней | HttpOnly | Получение новых
| | Cookie | Access Token'ов
Сравнение с Session-based аутентификацией
// Token-based (Stateless)
// ✅ Масштабируемо (не требует session storage)
// ✅ Подходит для микросервисов
// ✅ Работает для мобильных приложений
// ❌ Сложнее реализовать logout (token продолжит работать)
// Session-based (Stateful)
// ✅ Легко сделать logout (удалить session)
// ✅ Проще контролировать активные сессии
// ❌ Требует sync между серверами
// ❌ Масштабируется хуже
Практический совет
Для продакшена рекомендую:
- Использовать JWT (Access Token) с коротким TTL (15 минут)
- Хранить Refresh Token в secure HttpOnly Cookie
- Всегда использовать HTTPS
- Генерировать strong SECRET ключи
- Добавить blacklist для logout (Redis)
- Мониторить попытки подделки Token'ов
Понимание Access Token критично для безопасной разработки современных API приложений.