ThinkPHP6表单令牌防止重复提交

使用表单令牌需先开启session,session在ThinkPHP6中默认是未开启的,因为Token的值是会存到session中的,session是一个应用到整个浏览器的应用程序

在表单中使用表单令牌,首先需要设置一个隐藏域用来存放Token值

<input type="hidden" name="__token__" value="{:token()}" />

还可以直接使用

{:token_field()}

默认的令牌Token名称是__token__,如果需要自定义名称及令牌生成规则可以使用

//__hash__是要设置的token名称,md5是加密方式
{:token_field('__hash__', 'md5')}

 如果你没有使用默认的模板引擎,则需要自己生成表单隐藏域

AJAX令牌提交:

如果是AJAX提交表单,可以将Token设置到meta中

<meta name="csrf-token" content="{:token()}">

还可以写成

//会自动生成一个和上方一样的代码段
{:token_meta()}

在提交时需要在AJAX中定义请求头,不然后端无法获取准确的Token值,做不了防止重复提交工作,请求头可这样写

headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }

例子: 

//表单
<form role="form" style="width: 450px; margin: 0 auto;">
    //令牌
    {:token_meta()}

    <div class="form-group">
        <label for="name">角色名称</label>
        <input type="text" class="form-control rote_name" id="name" name="rote_name">
    </div>

    <div class="form-group">
        <label for="name">角色描述</label>
        <textarea class="form-control rote_test" name="rote_test"></textarea>
    </div>
    <button type="button" class="btn btn-default">提交</button>
</form>






//JQ代码段
<script>
    $('.btn').click(function () {
        //获取表单中的参数
        var rote_name = $('.rote_name').val();
        var rote_test = $('.rote_test').val();
        //ajax提交
        $.ajax({
            //请求地址
            url:"/add",
            //请求方式
            type:"post",
            //携带的参数
            data:{rote_name,rote_test},
            //请求头
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            //请求传参的格式
            dataType:"json",
            //接收返回值
            success:function (e) {
                //输出在控制台
                console.log(e)
            }
        })
    })
</script>

如果没有使用路由定义,可以在控制器里面手动进行令牌验证

//添加到有令牌过来的方法中
$check = $request->checkToken('__token__');
        
if(false === $check) {
    throw new ValidateException('invalid token');
}

如果使用路由了,可以在控制器中自动进行令牌验证

//添加到有令牌过来的方法中
$check = $request->checkToken('__token__', $request->param());
        
if(false === $check) {
    throw new ValidateException('invalid token');
}

也有许多人问未什么要在AJAX中使用请求头来传Token,因为在checkToken中存在别人已经封装好的方法,例如:

// Header验证
if ($this->header('X-CSRF-TOKEN') && $this->session->get($token) === $this->header('X-CSRF-TOKEN')) {
    // 防止重复提交
    $this->session->delete($token); // 验证完成销毁session
    return true;
}

这是在获取你前端页面AJAX提交中的headers中的Token值,在Token值一开始验证的时候,如果session中存在Token值且和请求头传递的值全等的话,会执行if语句中的代码,验证完成进行销毁session中的Token值,返回一个true

当你在表单连续点击两次时,第一次会进入上方的if语句中,而第二次会进入下方的if语句中

if (!$this->session->has($token)) {
    // 令牌数据无效
    return false;
}

第一次会正常返回你要返回的值,而第二次会抛出异常

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值