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

Spring MVC+Security环境下验证用户登录状态并管控AJAX接口权限

嘿,这个场景我太熟了!基于Spring MVC + Spring Security的项目里,防护AJAX接口其实就是把Spring Security的拦截能力和AJAX的响应特性结合起来,我给你梳理一套落地的方案:

核心防护思路

核心是要区分AJAX请求和普通请求的响应逻辑:普通请求可以重定向到登录页/403页面,但AJAX请求需要返回JSON格式的状态码和提示,避免前端出现跳转异常。下面分步骤实现:

1. 配置Spring Security的基础拦截规则

首先在你的SecurityConfig里,明确指定哪些AJAX接口需要认证/特定角色权限。假设你的AJAX接口都放在/api/**路径下,示例代码如下:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                // 所有AJAX接口必须先登录
                .antMatchers("/api/**").authenticated()
                // 特定接口仅允许ADMIN角色访问
                .antMatchers("/api/admin/**").hasRole("ADMIN")
                // 其他静态资源/页面允许匿名访问
                .anyRequest().permitAll()
            .and()
            // 保留你原有的登录/登出配置
            .formLogin()
                .loginPage("/login")
                .permitAll()
            .and()
            .logout()
                .permitAll();
    }
}

2. 自定义未认证请求的处理逻辑(AuthenticationEntryPoint)

Spring Security默认会把未认证请求重定向到登录页,但这对AJAX请求不友好。我们需要写一个自定义处理器,检测到AJAX请求时返回401状态码+JSON提示:

@Component
public class AjaxAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        // 通过请求头判断是否为AJAX请求
        if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("{\"code\":401,\"message\":\"请先登录系统\"}");
        } else {
            // 非AJAX请求还是走默认的登录页重定向
            response.sendRedirect(request.getContextPath() + "/login");
        }
    }
}

然后把这个处理器配置到SecurityConfig里:

@Autowired
private AjaxAuthenticationEntryPoint ajaxAuthenticationEntryPoint;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .exceptionHandling()
            .authenticationEntryPoint(ajaxAuthenticationEntryPoint)
        .and()
        // 其他原有配置...
}

3. 处理权限不足的情况(AccessDeniedHandler)

如果用户已经登录,但没有对应角色的权限,默认会返回403页面。同样,我们需要针对AJAX请求返回JSON提示:

@Component
public class AjaxAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.getWriter().write("{\"code\":403,\"message\":\"您没有权限访问该接口\"}");
        } else {
            // 非AJAX请求跳转到自定义403页面
            response.sendRedirect(request.getContextPath() + "/403");
        }
    }
}

同样把这个处理器配置到SecurityConfig:

@Autowired
private AjaxAccessDeniedHandler ajaxAccessDeniedHandler;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .exceptionHandling()
            .authenticationEntryPoint(ajaxAuthenticationEntryPoint)
            .accessDeniedHandler(ajaxAccessDeniedHandler)
        .and()
        // 其他原有配置...
}

4. 前端AJAX请求的统一响应处理

前端需要配合后端的状态码,做统一的提示或跳转。比如用jQuery的ajaxSetup全局处理:

$.ajaxSetup({
    complete: function(xhr) {
        if (xhr.status === 401) {
            alert("登录已过期,请重新登录");
            window.location.href = "/login";
        } else if (xhr.status === 403) {
            alert("您没有权限执行此操作");
        }
    }
});

额外安全提醒

  • 不要依赖前端权限控制:前端隐藏按钮/菜单只是优化体验,真正的权限校验必须靠后端的Spring Security拦截规则,避免用户直接构造请求访问接口。
  • 别忘了CSRF防护:Spring Security默认开启CSRF,前端AJAX请求需要携带CSRF令牌。可以在页面meta标签里配置,然后全局添加到请求头:
<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/>
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
});

内容的提问来源于stack exchange,提问作者mandy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:17:03