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

Laravel 8身份验证后提交表单出现CSRF Token Mismatch问题求助

Laravel 8注册流程中CSRF Token不匹配问题

在Laravel 8开发的注册流程里,用户选择不同账户类型后会弹出窗口完成手机身份验证。验证通过后弹窗关闭,自动提交POST方法的certForm表单跳转到对应注册页(用POST是为了防止未验证直接访问注册页),但此时触发了CSRF token mismatch错误。


相关代码

后端Livewire代码

public function verify(Request $request) {
    $identityVerification = new IdentityVerification();
    $iv = $identityVerification->verify($request->post());
    
    if($iv["Resultcd"] == "0000") {
        echo "<script>window.opener.document.getElementById('cert').value = 'ok';</script>";
        echo "<script>alert('DONE.');</script>";
        echo "<script>window.opener.document.certForm.submit();</script>";
        echo "<script>window.close();</script>";
    } else {
        echo "<script>alert('FAILED');</script>";
        echo "<script>location.href = '/login';</script>";
    }
}

public function render()
{
    return view('livewire.register-type');
}

前端视图代码

<div>
    <?php
    $Siteurl       = "Crack.com";
    ... some Code
    ?>

    <div>
        <main style="display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh;">
            <div>
                <div>
                    <p style="text-align: center; font-size: 1.5rem;">start</p>
                </div>
            </div>
            <div style="display: flex; gap: 1rem; text-align: center; margin-top: 2rem;">
                <div>
                    <div style="row-gap: 3rem; height: 100%; padding: 1rem; border: 1px solid rgb(110 174 211); border-radius: 1rem; display: flex; flex-direction: column; justify-content: center;">
                        <a href="javascript:verifyNumber('/register-school');">
                            <div style="display: flex; justify-content: space-around; align-items: center; padding: 1rem; background-color: rgb(110 174 211);">
                                <span>
                                    This Button
                                </span>
                                <img src="/assets/img/tap.png" width="40">
                            </div>
                        </a>
                    </div>
                </div>
                <div>
                    <div style="row-gap: 3rem; height: 100%; padding: 1rem; border: 1px solid rgb(235 185 185); border-radius: 1rem; display: flex; flex-direction: column; justify-content: center;">
                        <a href="javascript:verifyNumber('/register-company');">
                            <div onclick="" style="display: flex; justify-content: space-around; align-items: center; padding: 1rem; background-color: rgb(235 185 185);">
                                    This Button 222
                                </span>
                                <img src="/assets/img/tap.png" width="40">
                            </div>
                        </a>
                    </div>
                </div>
            </div>
        </main>
    </div>

    ... some Code
    <form name="payForm" accept-charset='euc-kr' method="GET">
        @csrf
        ... some Code
        <input type="hidden" name="Siteurl" id="Siteurl" value="{{$Siteurl ?? ''}}">
        <input type="hidden" name="type" id="type" value="">
        <input type="hidden" name="route" id="route" value="">
        <input type="hidden" name="_token" value="{{ csrf_token() }}">
    </form>
    
    <form method="post" name="certForm">
        @csrf
        <input type="hidden" name="cert" id="cert" value="">
        <input type="hidden" name="_token" value="{{ csrf_token() }}">
    </form>

    <script>
        function verifyNumber(route) {
            document.certForm.action = route;
            PAYMENT(document.payForm);
        }
    </script>
</div>

已尝试的方案

  • 为各注册页添加身份验证功能,但弹窗关闭后一段时间会出现页面过期提示
  • 修改certForm的提交方法,但无法保证必须验证的逻辑
  • 修改验证过期后的回调URL,问题依旧
  • 查询CSRF token过期与刷新机制,但未理解

问题原因及解决方案

核心原因

  1. Token过期或字段冲突:弹窗验证耗时较长时,原页面的CSRF Token可能过期;同时certForm里重复添加了_token字段(@csrf指令已自动生成,又手动加了一次),导致表单提交时Token值混乱。
  2. Session上下文不一致:弹窗页面若未和父页面共享Session,会导致提交的Token与Laravel存储的Session Token不匹配。

解决步骤

步骤1:清理重复的Token字段

删除certForm里手动添加的_token输入框,只保留@csrf指令,避免字段冲突:

<form method="post" name="certForm">
    @csrf
    <input type="hidden" name="cert" id="cert" value="">
</form>

步骤2:提交前刷新Token

由于弹窗验证可能耗时较久,原页面Token容易过期,修改后端验证成功的脚本,先获取父页面最新的Token再提交:

// 替换verify方法里的成功脚本
echo "<script>
    window.opener.document.getElementById('cert').value = 'ok';
    // 从父页面meta标签获取最新CSRF Token并更新表单
    const metaToken = window.opener.document.querySelector('meta[name=\"csrf-token\"]').content;
    const tokenInput = window.opener.document.certForm.querySelector('input[name=\"_token\"]');
    if(tokenInput) tokenInput.value = metaToken;
    alert('DONE.');
    window.opener.document.certForm.submit();
    window.close();
</script>";

确保父页面头部存在CSRF meta标签(Laravel默认已包含,缺失则添加):

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

步骤3:保证Session一致性

弹窗必须通过父页面的window.open()打开,而非直接跳转外部链接,这样才能维持和父页面相同的Session上下文,避免Token不匹配。

备选方案:使用一次性验证令牌

若上述方法仍有问题,可在验证通过后生成一个一次性令牌(存储在Session或Redis中),通过certForm提交该令牌,注册页验证令牌有效性而非依赖CSRF Token,既保证验证逻辑,又避开Token过期问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 06:00:20