You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Laravel Cashier(Stripe Checkout)更换银行卡操作步骤咨询

嘿,我刚好处理过类似的场景,用Laravel Cashier搭配Stripe Checkout来更新支付方式其实比你想的简单,而且完美契合你规避合规的需求——毕竟Stripe Checkout会帮你扛下大部分PCI合规的担子,不用自己碰敏感的银行卡信息。下面是一步步的详细操作,跟着来就行:

核心思路先理清

因为你用的是Stripe Checkout(而非Cashier默认的订阅管理页面),所以不能直接调用Cashier的updatePaymentMethod方法。核心逻辑是:通过Stripe Checkout的setup模式让用户在Stripe的安全页面输入新卡,Stripe会自动创建关联的支付方式,我们再通过Webhook回调把这个新支付方式设为用户订阅的默认支付方式。

步骤1:配置路由

先在routes/web.php里加两个路由:一个用来生成Checkout会话,另一个处理Stripe的Webhook回调:

Route::post('/user/update-payment-method', [UserController::class, 'createUpdatePaymentMethodSession'])
    ->middleware('auth');

Route::post('/stripe/update-payment-method-webhook', [UserController::class, 'handleUpdatePaymentMethodWebhook'])
    ->name('stripe.update-payment-method.webhook');
步骤2:生成Stripe Checkout会话

UserController里写生成会话的方法,重点是指定modesetup(仅用于设置支付方式,不创建订阅),并关联用户的Stripe Customer ID(Cashier已经帮你存在用户表的stripe_id字段里):

use Illuminate\Http\Request;
use Laravel\Cashier\Cashier;

public function createUpdatePaymentMethodSession(Request $request)
{
    $user = $request->user();

    // 如果你只针对订阅用户换卡,加这个判断
    if (! $user->subscribed()) {
        return redirect()->back()->with('error', '你没有活跃的订阅');
    }

    // 创建Stripe Checkout会话
    $session = Cashier::stripe()->checkout->sessions->create([
        'mode' => 'setup',
        'customer' => $user->stripe_id,
        'success_url' => route('dashboard').'?payment_updated=1', // 成功后跳转的页面
        'cancel_url' => route('dashboard').'?payment_updated=0', // 取消后跳转的页面
        'payment_method_types' => ['card'],
        'setup_intent_data' => [
            // 存一些元数据,方便后续Webhook里识别用户和订阅
            'metadata' => [
                'user_id' => $user->id,
                'subscription_id' => $user->subscription()->stripe_id,
            ],
        ],
    ]);

    // 跳转到Stripe Checkout页面
    return redirect()->away($session->url);
}
步骤3:处理Stripe Webhook回调

当用户在Stripe页面完成支付方式设置后,Stripe会发送checkout.session.completed事件到你的Webhook地址,我们需要监听这个事件,把新支付方式设为订阅的默认支付方式:

use Stripe\Event;
use Laravel\Cashier\Cashier;

public function handleUpdatePaymentMethodWebhook(Request $request)
{
    $payload = $request->getContent();
    $sigHeader = $request->header('Stripe-Signature');
    $webhookSecret = config('cashier.webhook_secret');

    // 验证Webhook签名,防止伪造请求
    try {
        $event = Cashier::stripe()->webhooks->constructEvent(
            $payload, $sigHeader, $webhookSecret
        );
    } catch (\Exception $e) {
        return response()->json(['error' => $e->getMessage()], 403);
    }

    if ($event->type === 'checkout.session.completed') {
        $session = $event->data->object;
        
        // 从元数据里取出用户和订阅信息
        $userId = $session->setup_intent->metadata['user_id'];
        $subscriptionId = $session->setup_intent->metadata['subscription_id'];
        $newPaymentMethodId = $session->setup_intent->payment_method;

        $user = \App\Models\User::find($userId);
        if (! $user) {
            return response()->json(['error' => '用户不存在'], 404);
        }

        $subscription = $user->subscription()->where('stripe_id', $subscriptionId)->first();
        if (! $subscription) {
            return response()->json(['error' => '订阅不存在'], 404);
        }

        // 更新订阅的默认支付方式
        $subscription->updateDefaultPaymentMethod($newPaymentMethodId);

        // 可选:删除旧的支付方式(如果需要清理的话)
        // $oldPaymentMethod = $user->defaultPaymentMethod();
        // if ($oldPaymentMethod && $oldPaymentMethod->id !== $newPaymentMethodId) {
        //     Cashier::stripe()->paymentMethods->detach($oldPaymentMethod->id);
        // }
    }

    return response()->json(['status' => 'success']);
}
步骤4:前端添加触发按钮

在用户的仪表盘页面加一个按钮,触发上面的POST请求:

<form action="/user/update-payment-method" method="POST">
    @csrf
    <button type="submit" class="btn btn-primary">更换银行卡</button>
</form>
测试与注意事项
  1. 配置Stripe Webhook:登录Stripe仪表盘,添加你的Webhook地址(https://你的域名/stripe/update-payment-method-webhook),并勾选checkout.session.completed事件,同时把Stripe提供的Webhook密钥填到config/cashier.phpwebhook_secret里。
  2. 测试用卡:用Stripe测试卡4242 4242 4242 4242(过期日期填未来的月份/年份,CVC随便填3位)来测试流程。
  3. 非订阅场景适配:如果用户没有订阅,只是想保存支付方式,去掉代码里的订阅相关判断,直接把支付方式关联到用户的Stripe Customer即可。

内容的提问来源于stack exchange,提问作者Jonathan Hyams

火山引擎 最新活动