CSRF 令牌每次刷新都不一样为什么还能通过校验?哪些请求方法需要令牌?单页应用读 cookie 再放进请求头为什么会 403?登录之后旧页面的令牌还有效吗?这篇在 Spring Boot 4.0.8、Spring Security 7 上逐个实测。
令牌的请求头名 = X-CSRF-TOKEN,请求参数名 = _csrf
同一个会话里连续取两次令牌:第 1 次 bBaOabKGfpXpHWoxAVZOEfgaqcm2YKB25W3hJJHSPtw1YXZkXXe2WNHlT6zEKVsHN3t6JJt4hKjUUphbgQiEFangXO8BAhcC(长度 96);第 2 次 8D9OUiYnsRzgawct71MfSU-Dlm8t4ZrbHtKzCnMlsjwNqPnjwV52Y0VEgCXNXzYb2X4rfCzhuw5P06L2erfWO0sX0A85y5iF(长度 96);两次相同:False
各种带法 POST /post:
不带令牌 → (403, '{"timestamp":"2026-10-20T04:15:56.910Z","status":403,"error":"Forbidden","path":"/post"}')
用请求头 X-CSRF-TOKEN 带第 1 次的令牌 → (200, 'posted')
用请求头带第 2 次的令牌(同一会话里另一个掩码) → (200, 'posted')
用请求头带一个随便写的令牌 → (403, '{"timestamp":"2026-10-20T04:15:56.925Z","status":403,"error":"Forbidden","path":"/post"}')
用表单参数 _csrf 带令牌 → (200, 'posted')
不同的 HTTP 方法(不带令牌):GET /who → 200;POST /post → 403;DELETE /item → 403;HEAD /who → 200;OPTIONS /who → 200每次取到的值不同但都有效;POST、DELETE 等需要令牌,GET、HEAD、OPTIONS 不需要。
登录页里的令牌 ZFkMvKn5xGXZ…(登录用的);登录成功 → HTTP 302
登录之后用登录页那个旧令牌 POST /post → (403, '{"timestamp":"2026-10-20T04:15:58.648Z","status":403,"error":"Forbidden","path":"/post"}')
登录之后取到新令牌再 POST /post → (200, 'posted')登录会换掉令牌,登录前缓存的旧令牌作废。
CookieCsrfTokenRepository.withHttpOnlyFalse() + 默认的请求处理器:Cookie XSRF-TOKEN = befb7652-11b…(长度 36);/csrf 接口给出的令牌长度 96
把 Cookie 里的值原样放进 X-XSRF-TOKEN 请求头 POST /post → (403, '{"timestamp":"2026-10-20T04:16:00.330Z","status":403,"error":"Forbidden","path":"/post"}')
用 /csrf 接口给出的令牌放进 X-XSRF-TOKEN 请求头 → (200, 'posted')
CookieCsrfTokenRepository.withHttpOnlyFalse() + CsrfTokenRequestAttributeHandler(明文):Cookie XSRF-TOKEN = c7311397-f98…(长度 36);/csrf 接口给出的令牌长度 36
把 Cookie 里的值原样放进 X-XSRF-TOKEN 请求头 POST /post → (200, 'posted')
用 /csrf 接口给出的令牌放进 X-XSRF-TOKEN 请求头 → (200, 'posted')cookie 里是原始令牌,默认处理器不认,要换成明文处理器或用 SPA 专用处理器。
csrf.ignoringRequestMatchers("/api/**"):POST /api/post 不带令牌 → (200, 'api posted');POST /post 不带令牌 → (403, '{"timestamp":"2026-10-20T04:16:03.719Z","status":403,"error":"Forbidden","path":"/post"}')
csrf.disable():POST /post 不带令牌 → (200, 'posted')ignoringRequestMatchers 按路径放行;disable 全部关闭。