Spring Security Cookie认证配置:禁用登录成功重定向并返回JSON
解决方案
要实现JSON凭证登录、返回JSON响应并禁用重定向,你需要调整Spring Security的认证过滤器逻辑,自定义成功/失败处理器,并修正鉴权规则的顺序。以下是分步实现方案:
1. 自定义认证成功/失败处理器
这两个处理器负责登录成功/失败时返回JSON响应,替代默认的重定向行为:
登录成功处理器
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class JsonAuthenticationSuccessHandler implements AuthenticationSuccessHandler { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_OK); Map<String, Object> responseBody = new HashMap<>(); responseBody.put("status", "success"); responseBody.put("message", "登录成功"); responseBody.put("username", authentication.getName()); objectMapper.writeValue(response.getWriter(), responseBody); } }
登录失败处理器
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class JsonAuthenticationFailureHandler implements AuthenticationFailureHandler { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); Map<String, Object> responseBody = new HashMap<>(); responseBody.put("status", "error"); responseBody.put("message", "登录失败:" + exception.getMessage()); objectMapper.writeValue(response.getWriter(), responseBody); } }
2. 修改自定义认证过滤器,支持JSON凭证解析
重写attemptAuthentication方法,从请求体读取JSON格式的用户名/密码:
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.Map; public class CustomAuthenticationProcessingFilter extends UsernamePasswordAuthenticationFilter { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { Map<String, String> credentials = objectMapper.readValue(request.getInputStream(), Map.class); String username = credentials.get("username"); String password = credentials.get("password"); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } catch (IOException e) { throw new RuntimeException("无法解析请求体", e); } } }
3. 修正SecurityFilterChain配置
调整鉴权规则顺序(先放行无需认证的接口),并为自定义过滤器绑定处理器:
public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { CustomAuthenticationProcessingFilter customAuthenticationProcessingFilter = new CustomAuthenticationProcessingFilter(); customAuthenticationProcessingFilter.setAuthenticationManager(authenticationManager); // 绑定自定义处理器,禁用重定向 customAuthenticationProcessingFilter.setAuthenticationSuccessHandler(new JsonAuthenticationSuccessHandler()); customAuthenticationProcessingFilter.setAuthenticationFailureHandler(new JsonAuthenticationFailureHandler()); // 指定登录请求的URL customAuthenticationProcessingFilter.setFilterProcessesUrl("/api/sign-in"); http .csrf().disable() .addFilterAt(customAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class) .authorizeRequests() // 先放行无需认证的接口,顺序不可颠倒 .antMatchers("/api/sign-up", "/api/sign-in").permitAll() // 其余接口必须认证 .anyRequest().authenticated() .and() .httpBasic() .authenticationEntryPoint(new RestAuthenticationEntryPoint()) .and() .logout() .logoutUrl("/api/sign-out") // 登出成功返回JSON .logoutSuccessHandler((request, response, authentication) -> { response.setContentType("application/json"); response.setStatus(HttpServletResponse.SC_OK); new ObjectMapper().writeValue(response.getWriter(), Map.of("status", "success", "message", "登出成功")); }); return http.build(); }
关键说明
- 鉴权规则顺序:必须先配置
permitAll的接口,再设置anyRequest().authenticated(),否则前者会被后者覆盖失效。 - 禁用重定向:通过自定义
AuthenticationSuccessHandler和AuthenticationFailureHandler,完全控制响应内容,避免Spring Security默认的重定向行为。 - JSON凭证解析:重写过滤器的
attemptAuthentication方法,从请求体读取JSON格式的认证信息,替代默认的表单参数解析。
内容的提问来源于stack exchange,提问作者Ammar S
相关产品推荐
相关产品推荐

