有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Spring Security中登录失败后停止转向登录页面

我有一个Spring引导应用程序,它有一个映射:

@GetMapping(path = "/users/{username}")
public User getUser(@PathVariable String username) {
    Optional<User> userOptional = userService.getByUsername(username);
    return userOptional.orElseThrow(() -> new UserNotFoundException("Username " + username + " is not found."));
}

我还有一个自定义异常处理程序:

@ExceptionHandler(UserNotFoundException.class)
public final ResponseEntity<Object> handleUserNotFoundException(Exception ex, WebRequest request) {
    var exception = new ExceptionResponse(LocalDateTime.now(), ex.getMessage(), request.getDescription(false));
    return new ResponseEntity<>(exception, HttpStatus.FORBIDDEN);
}

我的Web安全配置如下所示:

    http.cors().and().csrf().disable()
            .authorizeRequests()
             // Many matchers here
             // .....
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginProcessingUrl("/authenticate").usernameParameter("user").passwordParameter("pwd").permitAll();

然后我尝试用一个不存在的用户名登录

我所期望的是错误的单一JSON表示。但是,我总是会重新转换到登录页面

有人能告诉我如何防止Spring安全性转移我的注意力,而只是以JSON形式返回ResponseEntity吗


共 (1) 个答案

  1. # 1 楼答案

    您的应用程序可能比您共享的内容更多,但如果登录页面中的用户名无效,您的@GetMapping将不会被调用,您的@ExceptionHandler也不会被调用。这是因为Spring安全过滤器链不允许在身份验证之前调用应用程序代码

    为了处理身份验证错误,您需要注册一个AuthenticationFailureHandler,其中json响应需要手动写入。例如:

        public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
    
            private final ObjectMapper objectMapper = new ObjectMapper()
                    .registerModule(new JavaTimeModule())
                    .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    
            @Override
            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
                ExceptionResponse exceptionResponse = new ExceptionResponse(LocalDateTime.now(), exception.getMessage(), String.format("uri=%s", request.getServletPath()));
                String json = objectMapper.writeValueAsString(exceptionResponse);
                response.getWriter().write(json);
                response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            }
    
        }
    

    您可以直接在formLogin()配置中注册:

    http
        // ...
        .formLogin()
        .loginProcessingUrl("/authenticate").usernameParameter("user").passwordParameter("pwd").permitAll()
        .failureHandler(new CustomAuthenticationFailureHandler());
    

    有关筛选器链如何处理身份验证请求的更多信息,请查看docs