Как предотвратить вызов AuthenticationEntryPoint после AccessDeniedHandler?JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Как предотвратить вызов AuthenticationEntryPoint после AccessDeniedHandler?

Сообщение Anonymous »

Моя цель — вернуть 401, если пользователь предоставляет неверный JWT, и 403, если у него нет необходимых ролей для доступа к конечной точке (с использованием @RolesAllowed).
Изначально Spring вернул 403 для обоих. Затем я добавил конфигурациюExceptionHandling:
WebSecurityConfig.java:

Код: Выделить всё

...
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.rememberMe(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable)
.logout(AbstractHttpConfigurer::disable)
.cors(c -> c.configurationSource(corsConfigurationSource()))
.authorizeHttpRequests(c -> c
.requestMatchers(HttpMethod.OPTIONS).permitAll()
.requestMatchers(UNPROTECTED_PATHS).permitAll()
.anyRequest().authenticated()
)
.exceptionHandling(c -> c
.authenticationEntryPoint((request, response, authException) -> response.sendError(
HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage() // this one
))
.accessDeniedHandler((request, response, accessDeniedException) -> response.sendError(
HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage() // and this
))
)
.sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
...
JwtRequestFilter.java:

Код: Выделить всё

...
@Component
@RequiredArgsConstructor
@Slf4j
public class JwtRequestFilter extends OncePerRequestFilter {
private static final String HEADER_AUTHORIZATION = "Authorization";
private static final String AUTHORIZATION_PREFIX = "Bearer";

private final JwtService jwtService;
private final UserDao userDao;

@Override
protected void doFilterInternal(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain
) throws ServletException, IOException {
filterRequest(request);
filterChain.doFilter(request, response);
}

private void filterRequest(HttpServletRequest request) {
Authentication existAuthentication = SecurityContextHolder.getContext().getAuthentication();
if (existAuthentication != null && existAuthentication.isAuthenticated()) {
return;
}

String token = getToken(request);
if (token == null) {
return;
}

User user = jwtService.getUser(token).orElse(null);
if (user == null) {
return;
}

userDao.register(user);
setAuthentication(request, user);
}

@Nullable
private String getToken(HttpServletRequest request) {
String authorizationHeader = request.getHeader(HEADER_AUTHORIZATION);
if (authorizationHeader == null || !authorizationHeader.startsWith(AUTHORIZATION_PREFIX + " ")) {
return null;
}
return authorizationHeader.substring(7);
}

private static void setAuthentication(HttpServletRequest request, UserDetails userDetails) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
Теперь я всегда получаю 401. Я понял, что аутентификацияEntryPoint вызывается после accessDeniedHandler, когда создается AccessDeniedException.< /strong> Я предполагаю, что пользователь становится анонимным, если ему не удалось пройти авторизацию. С другой стороны, если указать неверный JWT (

Код: Выделить всё

AuthenticationException
выбрасывается) аутентификацияEntryPoint вызывается дважды.[/b] Мне это не кажется правильным поведением.
Как это предотвратить? p>
Я использую Spring Security v.6.2.3.
В настоящее время я использую обходной путь с ControllerAdvice:

Код: Выделить всё

@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity handleException(AccessDeniedException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
Таким образом, аутентификацияEntryPoint и accessDeniedHandler игнорируются.

Подробнее здесь: https://stackoverflow.com/questions/790 ... iedhandler
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»