ThinkPHP 6 的 token() 函数需显式调用、配合 session 启用及非 GET 请求才生效;默认三重混合策略生成一次性 token,POST 后失效,校验失败时须调用 TokenService::reset() 刷新。

ThinkPHP 6 的 token() 函数怎么用才安全
默认调用 token() 生成的隐藏域,不校验、不刷新、不绑定会话,等于没防。关键不是“有没有加”,而是“加了之后是否真生效”。
ThinkPHP 6 默认使用 think\middleware\ValidateToken 中间件做校验,但必须满足三个前提:
-
token()必须在模板中显式调用(不能靠自动注入) - 表单提交必须是 POST/PUT/DELETE 等非 GET 方法
- 当前请求必须已启动 session(
session_start()或框架自动开启)
常见错误是:在 CLI 环境或无 session 的 API 接口里调用 token(),它会返回空字符串,前端根本收不到 token 字段,后续校验必然失败。
为什么 token() 生成的值每次都不一样
ThinkPHP 6 的 token() 默认采用「会话绑定 + 时间戳扰动 + 随机因子」三重混合策略,不是简单哈希 session_id。这意味着:
- 同一用户连续两次访问同一页面,
token()返回不同值(防重放) - token 值有效期默认为 30 分钟(由
token_expire配置控制) - 若手动调用
TokenService::buildToken(),可传入$name参数指定字段名,但不建议复用 name,否则多个表单共用一个 token 会相互干扰
注意:token() 模板函数底层调用的是 think\helper\Str::random(16) 生成随机盐,并与 session_id、当前时间戳拼接后加密,所以不能靠客户端缓存 token 值来“优化性能”。
POST 提交后 token 失效,但页面要保留表单怎么办
典型场景:用户填完表单点提交,校验失败(如验证不通过),服务端返回原页面并提示错误——此时原 token 已被消耗,直接再次提交必报 TokenMismatchException。
正确做法不是“重用旧 token”,而是让服务端在渲染失败页面前主动刷新:
- 在控制器中手动调用
TokenService::reset()(TP6.1+)或TokenService::buildToken(true)强制重建 - 确保模板中仍是
{:token()},它会自动读取最新值 - 不要在 JS 中提前读取并固化
input[name="__token"]的 value,那会锁死过期 token
如果用了 AJAX 提交,建议把 token 获取逻辑封装成独立接口(如 /api/token),每次提交前先 fetch 一次,避免页面级生命周期干扰。
自定义 token 字段名和存储位置的风险点
可以通过配置 token_name 和 token_type 改变默认行为,但改了就得同步改中间件和前端逻辑:
-
token_name默认是__token,若改成_csrf,则中间件只认这个 key,且所有表单都得统一 -
token_type可设为header,此时 token 不走表单隐藏域,而从请求头X-CSRF-TOKEN读取——适合前后端分离项目,但需前端主动设置 header - 若同时启用
token_on为false,中间件将跳过所有 token 校验,哪怕表单里写了__token也没用
最易忽略的一点:当使用多级子域名(如 admin.example.com 和 api.example.com)时,session 默认不跨域,token 校验会因 session_id 不一致而失败——这不是框架 bug,是 Cookie 作用域限制,得配 session.domain 才能解决。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











