Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
JWT авторизация
JWT (JSON Web Token) — это способ передачи информации между сторонами в виде JSON объекта, подписанного цифровой подписью. Это современный стандарт для аутентификации и авторизации в REST API и микросервисах.
Структура JWT
JWT состоит из трёх частей, разделённых точками: header.payload.signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Header (заголовок) — описывает алгоритм и тип токена:
{
"alg": "HS256",
"typ": "JWT"
}
Payload (полезная нагрузка) — содержит claims (утверждения):
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516242622
}
Signature (подпись) — обеспечивает целостность токена:
HMAC-SHA256(base64(header) + "." + base64(payload), secret_key)
Как работает JWT авторизация
- Аутентификация: Пользователь отправляет логин/пароль
- Создание токена: Сервер проверяет credentials и генерирует JWT
- Отправка клиенту: Клиент сохраняет токен (localStorage, sessionStorage или cookie)
- Использование токена: Клиент отправляет токен в заголовке:
Authorization: Bearer <token> - Проверка на сервере: Сервер верифицирует подпись и проверяет expiration
Реализация с Spring Security
@Configuration
@EnableWebSecurity
public class JwtSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(
new JwtAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class
)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
Генерация JWT токена
@Service
public class JwtTokenProvider {
@Value("${jwt.secret}")
private String jwtSecret;
@Value("${jwt.expiration}")
private long jwtExpirationMs;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put("roles", userDetails.getAuthorities());
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpirationMs);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}
}
Фильтр для обработки JWT
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenProvider tokenProvider;
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = extractTokenFromRequest(request);
if (jwt != null && tokenProvider.validateToken(jwt)) {
String username = tokenProvider.getUsernameFromToken(jwt);
// Создаём Authentication объект
Authentication auth = new UsernamePasswordAuthenticationToken(
username, null, new ArrayList<>()
);
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
logger.error("Cannot set user authentication", e);
}
filterChain.doFilter(request, response);
}
private String extractTokenFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
Контроллер для login
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private JwtTokenProvider tokenProvider;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
// Проверяем credentials (в реальной системе через AuthenticationManager)
String token = tokenProvider.generateToken(
new User(loginRequest.getUsername(), "")
);
return ResponseEntity.ok(
new JwtAuthResponse(token, "Bearer", jwtExpirationMs / 1000)
);
}
}
class JwtAuthResponse {
public String accessToken;
public String tokenType = "Bearer";
public long expiresIn;
public JwtAuthResponse(String accessToken, String tokenType, long expiresIn) {
this.accessToken = accessToken;
this.tokenType = tokenType;
this.expiresIn = expiresIn;
}
}
Преимущества JWT
- Stateless: Сервер не хранит сессии, легче масштабировать
- Мобильный friendly: Хорошо работает с мобильными приложениями
- Cross-domain: Можно использовать в CORS сценариях
- Самодостаточный: Содержит всю необходимую информацию
- Безопасный: Подписан и может быть зашифрован
Недостатки JWT
- Невозможно отозвать: Токен действителен до истечения (нужна чёрный список)
- Размер: Больше, чем обычная сессия ID
- Утечка данных: Payload кодируется, но не шифруется
Лучшие практики
- Используй HTTPS для всех коммуникаций
- Храни токен в secure cookies или sessionStorage (не localStorage)
- Реализуй refresh token для обновления доступа
- Устанавливай короткое время expiration (15-30 минут)
- Добавь чёрный список для отозванных токенов при необходимости