Spring Security 登录失败后如何停止跳转到登录页面
Posted
技术标签:
【中文标题】Spring Security 登录失败后如何停止跳转到登录页面【英文标题】:How to stop being diverted to login page after unsuccessful login in Spring Security 【发布时间】:2021-07-26 13:15:20 【问题描述】:我有一个带有映射的 Spring Boot 应用程序:
@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);
我的 WebSecurityConfig 是这样的:
http.cors().and().csrf().disable()
.authorizeRequests()
// Many matchers here
// .....
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/authenticate").usernameParameter("user").passwordParameter("pwd").permitAll();
然后我尝试使用不存在的用户名登录。
我所期望的是错误的单个 JSON 表示。但是,我总是会重新转到登录页面。
有人可以建议我如何防止 Spring Security 转移我的注意力,而是只返回 JSON 表单中的 ResponseEntity 吗?
【问题讨论】:
【参考方案1】:您的应用程序可能比您共享的内容更多,但如果登录页面中的用户名无效,您的@GetMapping
将不会被调用,您的@ExceptionHandler
也不会被调用。这是因为 Spring Security 过滤器链永远不允许在身份验证之前调用您的应用程序代码。
为了处理身份验证错误,您需要注册一个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,了解有关过滤器链如何处理身份验证请求的更多信息。
【讨论】:
以上是关于Spring Security 登录失败后如何停止跳转到登录页面的主要内容,如果未能解决你的问题,请参考以下文章
使用 Grails Spring Security Rest 插件时如何获取客户端登录失败的原因?
Spring Boot + Spring Security Restful 登录
防止 Spring Security 在登录/注销后进行 302 重定向