Почему у меня не выводится ответ с ошибкой авторизации?
У меня есть авторизованный запрос
DELETE http://localhost:8080/api/v1/users/delete/1
Вот контроллер
@DeleteMapping("/delete/{id}")
public ResponseEntity<UserResponseDTO> deleteUser(@PathVariable("id") Long id) {
return ResponseEntity.ok(userService.delete(id));
}
Он возвращает ответ
{
"type": "about:blank",
"title": "Forbidden",
"status": 403,
"detail": "An unexpected error occurred: Доступ запрещен",
"instance": "/api/v1/users/delete/1"
}
Но когда я подкрепляю заголовок авторизации заведемо неверный
DELETE http://localhost:8080/api/v1/users/delete/1
Authorization:Basic YWRtaW5ADZXhhbXBsZS5jb206YWRtaW4= - неверный base64- строка
Вот какой ответ мне возвращается
DELETE http://localhost:8080/api/v1/users/delete/1
Authorization:Basic YWRtaW5ADZXhhbXBsZS5jb206YWRtaW4=
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
WWW-Authenticate: Basic realm="Realm"
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Mon, 04 Nov 2024 10:05:56 GMT
<Response body is empty>
С верным заголовком все работает как надо Почему возращается пустое тело и код ответа 200 Если я убираю глобальный обработчик ошибок,то ничего не меняется. Возможно это связано с entryPoint?
Должен вернуться 401 / 403 и тело ответа с ошибкой
Почему у меня не обрабатывается ошибка ?
org.springframework.security.authentication.BadCredentialsException: Invalid basic authentication token
org.springframework.security.authentication.BadCredentialsException: Invalid basic authentication token
org.springframework.security.authentication.BadCredentialsException: Invalid basic authentication token
у меня есть глобальный обработчик ошибок
@RestControllerAdvice(basePackages = "ru.oniskovet.carsforum.controllers")
public class GlobalExceptionHandler {
@ExceptionHandler({IllegalArgumentException.class, NoSuchElementException.class, NoHandlerFoundException.class})
ResponseEntity<ProblemDetail> handleNotFoundErrors(Exception e) {
ProblemDetail problemDetail = ProblemDetail.forStatus(404);
problemDetail.setTitle("Not found");
problemDetail.setDetail("An unexpected error occurred: " + e.getLocalizedMessage());
return ResponseEntity.status(404)
.body(problemDetail);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
ResponseEntity<Object> handleMethodValidationException(Exception e) {
ProblemDetail problemDetail = ProblemDetail.forStatus(400);
problemDetail.setTitle("Validation Error");
problemDetail.setDetail("An unexpected error occurred: " + e.getLocalizedMessage() );
return ResponseEntity.badRequest()
.body(problemDetail);
}
@ExceptionHandler({BadRequestException.class, MissingRequestValueException.class})
ResponseEntity<Object> handleMethodClientException(Exception e) {
ProblemDetail problemDetail = ProblemDetail.forStatus(400);
problemDetail.setTitle("Validation Error");
problemDetail.setDetail("An unexpected error occurred: " + e.getLocalizedMessage() );
return ResponseEntity.badRequest()
.body(problemDetail);
}
@ExceptionHandler({UsernameNotFoundException.class, BadCredentialsException.class})
ResponseEntity<ProblemDetail> handleAuthenticationException(Exception e) {
ProblemDetail problemDetail = ProblemDetail.forStatus(401);
problemDetail.setTitle("unauthorized");
problemDetail.setDetail("An unexpected error occurred: " + e.getLocalizedMessage() );
return ResponseEntity.status(401)
.body(problemDetail);
}
@ExceptionHandler(InsufficientAuthenticationException.class)
ResponseEntity<ProblemDetail> handleInsufficientAuthenticationException(InsufficientAuthenticationException e) {
ProblemDetail problemDetail = ProblemDetail.forStatus(401);
problemDetail.setTitle("unauthorized");
problemDetail.setDetail("An unexpected error occurred: " + e.getLocalizedMessage() );
return ResponseEntity.status(401)
.body(problemDetail);
}
@ExceptionHandler(AccountStatusException.class)
ResponseEntity<ProblemDetail> handleAccountStatusException(AccountStatusException e) {
ProblemDetail problemDetail = ProblemDetail.forStatus(401);
problemDetail.setTitle("unauthorized");
problemDetail.setDetail("An unexpected error occurred: " + e.getLocalizedMessage() );
return ResponseEntity.status(401)
.body(problemDetail);
}
@ExceptionHandler(AccessDeniedException.class)
ResponseEntity<ProblemDetail> handleAccessDeniedException(AccessDeniedException e) {
ProblemDetail problemDetail = ProblemDetail.forStatus(403);
problemDetail.setTitle("Forbidden");
problemDetail.setDetail("An unexpected error occurred: " + e.getLocalizedMessage() );
return ResponseEntity.status(403)
.body(problemDetail);
}
@ExceptionHandler(Exception.class)
ResponseEntity<ProblemDetail> handleGenericExceptions(Exception e) {
ProblemDetail problemDetail = ProblemDetail.forStatus(500);
problemDetail.setTitle("Internal Server Error");
problemDetail.setDetail("An unexpected error occurred: " + e.getLocalizedMessage());
return ResponseEntity.status(500)
.body(problemDetail);
}
}
Вот мой конфиг безопасности
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig {
private UserDetailsService userDetailsService;
private AuthenticationEntryPoint authenticationEntryPoint;
@Autowired
public WebSecurityConfig(UserDetailsService userDetailsService, AuthenticationEntryPoint authenticationEntryPoint) {
this.userDetailsService = userDetailsService;
this.authenticationEntryPoint = authenticationEntryPoint;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.anyRequest().permitAll()
)
.csrf().disable() // Отключаем CSRF защиту, так как для HTTP Basic её включать не нужно
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // Используем stateless сессии для Basic Auth
)
.authenticationProvider(authenticationProvider())
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
return http.build();
}
@Bean
public AuthenticationManager authenticationManagerBean(AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
@Bean
public PasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(bCryptPasswordEncoder());
return provider;
}
}
Вот мой EntryPoint
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final HandlerExceptionResolver resolver;
public CustomAuthenticationEntryPoint(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
this.resolver = resolver;
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
response.addHeader("WWW-Authenticate", "Basic realm=\"Realm\"");
resolver.resolveException(request, response, null, authException);
}
}
Авторизация у меня настроена через аннотации над методами сервисов
public interface UserService {
@Secured("ROLE_ADMIN")
UserResponseDTO delete(Long id);
@PreAuthorize("hasRole('ROLE_ADMIN') or ((hasRole('ROLE_USER')" +
"and @articleService.isHasAccessToArticle(authentication.principal.id, #id)))")
UserResponseDTO update(Long id, UserRequestDTO user);
@PermitAll
UserResponseDTO getById(Long id);
@PermitAll
UserResponseDTO create(UserRequestDTO user);
@PermitAll
List<UserResponseDTO> getAll();
@PermitAll
List<UserResponseDTO> getALLByUsername(String username);
User get(Long id);
}