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

Struts 6.2.0中CSRF令牌实现遇invalid.token错误,求解决方案

解决Struts 6.2.0 CSRF防护返回invalid.token的问题

核心问题分析

你的配置存在几个关键问题,导致token验证失败:

  • 拦截器栈配置无效:struts.xml中定义的defaultSecurityStack是空栈,既没有包含params、workflow等基础拦截器,也未整合token拦截器,导致Action执行时缺少必要的上下文处理。
  • 拦截器引用冲突且顺序错误:TokenInterceptor和TokenSessionStoreInterceptor是互斥使用的,不能同时添加到Action的拦截器引用中;前者验证失败直接返回invalid.token,后者会将请求暂存到session中避免重复提交,同时处理token验证逻辑。
  • 全局异常映射覆盖token拦截器默认结果:TokenInterceptor验证失败会返回invalid.token结果,但你的全局异常映射将所有Exception都导向错误页,导致无法正确回到登录页重新提交。

修正方案

1. 修复struts.xml拦截器栈配置

将基础拦截器和token拦截器整合到默认栈,确保所有Action继承正确的拦截器逻辑:

<package name="struts-security" abstract="true" extends="struts-default">
  <interceptors>
    <!-- 整合默认栈与tokenSessionStore拦截器 -->
    <interceptor-stack name="defaultSecurityStack">
      <interceptor-ref name="defaultStack"/>
      <interceptor-ref name="tokenSessionStore"/>
    </interceptor-stack>
  </interceptors>

  <default-interceptor-ref name="defaultSecurityStack"/>

  <global-results>
    <result name="error">/error401.jsp</result>
    <!-- 添加token验证失败的全局结果,指向登录页 -->
    <result name="invalid.token" type="tiles">login.Login</result>
  </global-results>

  <global-exception-mappings>
    <!-- 缩小异常范围,避免覆盖token拦截器的结果处理 -->
    <exception-mapping result="error" exception="java.lang.RuntimeException"/>
  </global-exception-mappings>
</package>

2. 简化LoginAction的拦截器配置

移除重复的拦截器引用,因为默认栈已包含tokenSessionStore:

@Namespace("/common")
@Action("Login")
@Results({
  @Result(name = "input", location = "login.Login", type = "tiles"),
  // 可选:单独定义当前Action的token失败结果
  @Result(name = "invalid.token", location = "login.Login", type = "tiles")
})
public class LoginAction extends ActionSupport {
    // 业务逻辑代码
}

3. 确认login.jsp表单配置正确

确保s:form的action属性正确指向LoginAction,s:token标签在表单内部(现有代码已满足,补充完整示例):

<%@ taglib prefix="s" uri="/struts-tags"%>
<s:form action="Login" method="post" validate="true" theme="simple" name="form" id="paraFrm">
  <s:token />
  <!-- 其他表单字段 -->
  <s:textfield name="username" label="用户名"/>
  <s:password name="password" label="密码"/>
  <s:submit value="登录"/>
</s:form>

4. 可选:优化Token行为配置

在struts.properties中添加以下参数,调整token的存储和过期规则:

# token的session存储键名
struts.token.name=token
# token过期时间(毫秒,此处为1小时)
struts.token.session.expiration=3600000

关键注意事项

  • 不要同时使用TokenInterceptor和TokenSessionStoreInterceptor:推荐用TokenSessionStoreInterceptor处理重复提交,若需严格验证token,单独使用TokenInterceptor并处理invalid.token结果。
  • 确保Session正常工作:token依赖Session存储,若Session失效或未正确初始化,会导致验证失败。
  • 必须通过Struts标签生成表单:s:token会自动渲染隐藏字段并绑定Session中的token值,手动写HTML表单无法生成有效token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:24:56