← Назад к вопросам
Что такое респонс-код 401?
2.0 Middle🔥 111 комментариев
#SOLID и паттерны проектирования#Spring Boot и Spring Data
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
HTTP статус-код 401 Unauthorized
401 Unauthorized — это HTTP статус-код, который указывает, что запрос требует аутентификации (authentication), но клиент либо не предоставил учётные данные, либо предоставил недействительные. Это означает, что сервер не смог идентифицировать личность клиента.
Разница между 401 и 403
Часто путают 401 и 403:
- 401 Unauthorized — клиент не аутентифицирован (не прошёл проверку учётных данных)
- 403 Forbidden — клиент аутентифицирован, но не имеет прав доступа к ресурсу
401 = Кто ты? (нужна аутентификация)
403 = Я знаю кто ты, но ты не можешь это делать (нет авторизации)
Сценарии возврата 401
1. Отсутствие токена аутентификации
// REST контроллер, защищённый от неавторизованного доступа
@RestController
@RequestMapping("/api/v1")
public class UserController {
@GetMapping("/me")
public ResponseEntity<UserDTO> getCurrentUser(
@RequestHeader(value = "Authorization", required = false) String authHeader) {
if (authHeader == null || authHeader.isEmpty()) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
String token = authHeader.replace("Bearer ", "");
try {
User user = authenticateToken(token);
return ResponseEntity.ok(new UserDTO(user));
} catch (InvalidTokenException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
}
2. Истёк срок действия токена
@Component
public class JwtValidator {
public boolean isTokenValid(String token) {
try {
Claims claims = Jwts.parserBuilder()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(token)
.getBody();
// Проверка срока истечения
if (claims.getExpiration().before(new Date())) {
throw new ExpiredJwtException(null, null, "Token expired");
}
return true;
} catch (ExpiredJwtException e) {
// Вернуть 401
return false;
} catch (SignatureException | MalformedJwtException e) {
// Вернуть 401
return false;
}
}
}
3. Неправильные учётные данные (Basic Auth)
@RestController
public class LoginController {
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
User user = userRepository.findByUsername(request.getUsername()).orElse(null);
if (user == null || !passwordEncoder.matches(request.getPassword(), user.getPassword())) {
// 401 — не смогли аутентифицировать
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(new ErrorResponse("Invalid username or password"));
}
String token = generateJwt(user);
return ResponseEntity.ok(new LoginResponse(token));
}
}
Обработка 401 в клиентском коде
public class ApiClient {
public UserDTO getUser(String userId) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users/" + userId))
.header("Authorization", "Bearer " + getToken())
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 401) {
// Токен истёк, попробовать обновить
refreshToken();
// Повторить запрос с новым токеном
return getUser(userId);
}
if (response.statusCode() == 200) {
return parseJson(response.body(), UserDTO.class);
}
throw new ApiException("Unexpected status: " + response.statusCode());
}
}
Spring Security и обработка 401
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers("/api/login", "/api/register").permitAll()
.requestMatchers("/api/**").authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> {
// Обработка 401
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.getWriter().write("{\"error\":\"Unauthorized\"}");
})
.and()
.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
Типичные причины 401
| Причина | Пример |
|---|---|
| Отсутствие токена | Header Authorization не передан |
| Истёк токен | JWT token expired |
| Неверная подпись | Токен подделан |
| Неверные credentials | Неправильный пароль при Basic Auth |
| Токен в неправильном формате | "Token" вместо "Bearer <token>" |
| Токен не для этого API | Токен от другого сервиса |
REST API Best Practices
// Хорошая практика: вернуть 401 с объяснением
@ExceptionHandler(AuthenticationException.class)
public ResponseEntity<ErrorResponse> handleAuthError(AuthenticationException e) {
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body(new ErrorResponse(
"Unauthorized",
"Authentication required. Please provide valid credentials.",
HttpStatus.UNAUTHORIZED.value()
));
}
// Добавить WWW-Authenticate header
@ExceptionHandler(AuthenticationException.class)
public ResponseEntity<ErrorResponse> handleAuthErrorWithHeader(AuthenticationException e) {
return ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.header("WWW-Authenticate", "Bearer realm=\"api\"")
.body(new ErrorResponse("Unauthorized"));
}
Когда использовать 401
- Клиент не предоставил аутентификационные данные
- Предоставленные учётные данные недействительны
- Сессия истекла
- Токен истёк или поддельный
Понимание 401 статуса критично при работе с защищённые API, OAuth 2.0 и JWT токенами.