You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 05:22:45