Stripe支付集成:触发SCA/3D Secure重定向认证方案及跳转URL来源咨询
问题:如何处理Stripe支付中的3D/SCA认证重定向?
我当前的代码可以完成普通银行卡支付,但无法处理需要3D/SCA认证的欧洲地区银行卡。想知道是否有办法让Stripe将用户重定向至发卡银行进行身份认证以完成交易,另外根据Stripe官方文档的说明,相关返回结构包含next_action字段,想确认Stripe SDK是否会自动获取发卡银行的跳转URL,还是需要开发者手动提供该信息。
现有代码文件
1. StripePayment.php
<?php require_once 'vendor/autoload.php'; use \Stripe\Stripe; use \Stripe\Customer; use \Stripe\ApiOperations\Create; use \Stripe\Charge; class StripePayment { private $apiKey; private $stripeService; public function __construct() { require_once "config.php"; $this->apiKey = STRIPE_SECRET_KEY; $this->stripeService = new \Stripe\Stripe(); $this->stripeService->setVerifySslCerts(false); $this->stripeService->setApiKey($this->apiKey); } public function addCustomer($customerDetailsAry) { $customer = new Customer(); $customerDetails = $customer->create($customerDetailsAry); return $customerDetails; } public function chargeAmountFromCard($cardDetails) { $customerDetailsAry = array( 'email' => $cardDetails['email'], 'source' => $cardDetails['token'] ); $customerResult = $this->addCustomer($customerDetailsAry); $charge = new Charge(); $cardDetailsAry = array( 'customer' => $customerResult->id, 'amount' => $cardDetails['amount']*100 , 'currency' => $cardDetails['currency_code'], 'description' => $cardDetails['item_name'], 'metadata' => array( 'order_id' => $cardDetails['item_number'] ) ); $result = $charge->create($cardDetailsAry); return $result->jsonSerialize(); } }
2. 支付功能调用代码
<?php ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); require_once "config.php"; if (!empty($_POST["token"])) { require_once 'StripePayment.php'; $stripePayment = new StripePayment(); $stripeResponse = $stripePayment->chargeAmountFromCard($_POST); require_once "DBController.php"; $dbController = new DBController(); $amount = $stripeResponse["amount"] /100; $param_type = 'ssdssss'; $param_value_array = array( $_POST['email'], $_POST['item_number'], $amount, $stripeResponse["currency"], $stripeResponse["balance_transaction"], $stripeResponse["status"], json_encode($stripeResponse) );
3. Stripe支付表单及前端代码
<form id="frmStripePayment" action="" method="post"> <div class="field-row"> <label>Card Holder Name</label> <span id="card-holder-name-info" class="info"></span><br> <input type="text" id="name" name="name" class="demoInputBox"> </div> <div class="field-row"> <label>Email</label> <span id="email-info" class="info"></span><br> <input type="text" id="email" name="email" class="demoInputBox"> </div> <div class="field-row"> <label>Card Number</label> <span id="card-number-info" class="info"></span><br> <input type="text" id="card-number" name="card-number" class="demoInputBox"> </div> <div class="field-row"> <div class="contact-row column-right"> <label>Expiry Month / Year</label> <span id="userEmail-info" class="info"></span><br> <select name="month" id="month" class="demoSelectBox"> <option value="02">02</option> <option value="03">03</option> <option value="04">04</option> <option value="05">05</option> <option value="06">06</option> <option value="07">07</option> <option value="08">08</option> <option value="08">08</option> <option value="08">08</option> <option value="09">09</option> <option value="10">10</option> <option value="11">11</option> <option value="12">12</option> </select> <select name="year" id="year" class="demoSelectBox"> <option value="21">2021</option> <option value="22">2022</option> <option value="23">2023</option> <option value="24">2024</option> <option value="25">2025</option> <option value="26">2026</option> <option value="27">2027</option> <option value="28">2028</option> <option value="29">2029</option> <option value="30">2030</option> </select> </div> <div class="contact-row cvv-box"> <label>CVC</label> <span id="cvv-info" class="info"></span><br> <input type="text" name="cvc" id="cvc" class="demoInputBox cvv-input"> </div> </div> <div> <input type="submit" name="pay_now" value="Submit" id="submit-btn" class="btnAction" onClick="stripePay(event);"> <div id="loader"> <img alt="loader" src="LoaderIcon.gif"> </div> </div> <input type='hidden' name='amount' value='1100'> <input type='hidden' name='currency_code' value='USD'> <input type='hidden' name='item_name' value='Solidroof Product'> <input type='hidden' name='item_number' value='SCA#Test'> </form> <script> function cardValidation () { var valid = true; var name = $('#name').val(); var email = $('#email').val(); var cardNumber = $('#card-number').val(); var month = $('#month').val(); var year = $('#year').val(); var cvc = $('#cvc').val(); $("#error-message").html("").hide(); if (name.trim() == "") { valid = false; } if (email.trim() == "") { valid = false; } if (cardNumber.trim() == "") { valid = false; } if (month.trim() == "") { valid = false; } if (year.trim() == "") { valid = false; } if (cvc.trim() == "") { valid = false; } if(valid == false) { $("#error-message").html("All Fields are required").show(); } return valid; } //set your publishable key Stripe.setPublishableKey("<?php echo STRIPE_PUBLISHABLE_KEY; ?>"); //callback to handle the response from stripe function stripeResponseHandler(status, response) { if (response.error) { //enable the submit button $("#submit-btn").show(); $( "#loader" ).css("display", "none"); //display the errors on the form $("#error-message").html(response.error.message).show(); } else { //get token id var token = response['id']; //insert the token into the form $("#frmStripePayment").append("<input type='hidden' name='token' value='" + token + "' />"); //submit form to the server $("#frmStripePayment").submit(); } } function stripePay(e) { e.preventDefault(); var valid = cardValidation(); if(valid == true) { $("#submit-btn").hide(); $( "#loader" ).css("display", "inline-block"); Stripe.createToken({ number: $('#card-number').val(), cvc: $('#cvc').val(), exp_month: $('#month').val(), exp_year: $('#year').val() }, stripeResponseHandler); //submit from callback return false; } } </script>
解决方案:实现3D/SCA认证重定向流程
先直接回答你的核心疑问:Stripe SDK会自动生成发卡银行的跳转URL,完全不需要你手动提供。你的现有代码只是缺少了处理next_action响应的逻辑,所以才无法完成3D认证流程。下面是具体的修改步骤:
1. 修改后端StripePayment.php的支付方法
当创建Charge时,如果需要3D认证,Stripe会返回带有next_action的响应,我们需要捕获这个信息并返回给前端,同时保存Charge ID用于后续验证:
public function chargeAmountFromCard($cardDetails) { $customerDetailsAry = array( 'email' => $cardDetails['email'], 'source' => $cardDetails['token'] ); $customerResult = $this->addCustomer($customerDetailsAry); $charge = new Charge(); $cardDetailsAry = array( 'customer' => $customerResult->id, 'amount' => $cardDetails['amount']*100 , 'currency' => $cardDetails['currency_code'], 'description' => $cardDetails['item_name'], 'metadata' => array( 'order_id' => $cardDetails['item_number'] ), // 关键配置:启用手动3D认证流程 'confirmation_method' => 'manual', 'confirm' => true, // 指定认证完成后Stripe跳转回你的页面 'return_url' => 'https://你的域名/payment_return.php' ); try { $result = $charge->create($cardDetailsAry); $response = $result->jsonSerialize(); // 检查是否需要跳转至银行认证 if (isset($response['next_action']) && $response['next_action']['type'] === 'redirect_to_url') { $response['requires_redirect'] = true; // 保存Charge ID到会话,后续验证用 session_start(); $_SESSION['charge_id'] = $response['id']; } else { $response['requires_redirect'] = false; } return $response; } catch (\Stripe\Exception\CardException $e) { // 捕获卡相关错误(包括认证失败) return array('error' => $e->getMessage()); } }
2. 修改后端支付调用逻辑
处理返回的响应,根据是否需要重定向,返回不同的结果给前端:
if (!empty($_POST["token"])) { session_start(); require_once 'StripePayment.php'; $stripePayment = new StripePayment(); $stripeResponse = $stripePayment->chargeAmountFromCard($_POST); if (isset($stripeResponse['requires_redirect']) && $stripeResponse['requires_redirect']) { // 返回跳转信息给前端 echo json_encode(array( 'status' => 'redirect', 'redirect_url' => $stripeResponse['next_action']['redirect_to_url']['url'] )); exit; } elseif (!isset($stripeResponse['error'])) { // 支付成功,执行数据库保存逻辑 require_once "DBController.php"; $dbController = new DBController(); $amount = $stripeResponse["amount"] /100; $param_type = 'ssdssss'; $param_value_array = array( $_POST['email'], $_POST['item_number'], $amount, $stripeResponse["currency"], $stripeResponse["balance_transaction"], $stripeResponse["status"], json_encode($stripeResponse) ); // 执行数据库插入操作... echo json_encode(array('status' => 'success')); exit; } else { // 返回错误信息 echo json_encode(array('status' => 'error', 'message' => $stripeResponse['error'])); exit; } }
3. 修改前端AJAX提交逻辑
不再直接提交表单,改用AJAX异步处理,方便接收跳转指令:
function stripeResponseHandler(status, response) { if (response.error) { $("#submit-btn").show(); $( "#loader" ).css("display", "none"); $("#error-message").html(response.error.message).show(); } else { var token = response['id']; // 用AJAX提交支付数据 $.ajax({ url: window.location.href, // 指向当前处理页面 type: 'POST', data: { token: token, email: $('#email').val(), amount: $('input[name="amount"]').val(), currency_code: $('input[name="currency_code"]').val(), item_name: $('input[name="item_name"]').val(), item_number: $('input[name="item_number"]').val(), name: $('#name').val() }, dataType: 'json', success: function(data) { $("#submit-btn").show(); $( "#loader" ).css("display", "none"); if (data.status === 'redirect') { // 跳转到银行认证页面 window.location.href = data.redirect_url; } else if (data.status === 'success') { // 支付成功,跳转至结果页 window.location.href = 'payment_success.php'; } else { $("#error-message").html(data.message).show(); } }, error: function() { $("#submit-btn").show(); $( "#loader" ).css("display", "none"); $("#error-message").html('支付处理失败,请稍后重试').show(); } }); } }
4. 添加认证回调处理页面(payment_return.php)
用户完成银行认证后,Stripe会跳转回你指定的return_url,这里需要验证Charge的最终状态:
<?php session_start(); require_once 'vendor/autoload.php'; require_once 'config.php'; \Stripe\Stripe::setApiKey(STRIPE_SECRET_KEY); if (!isset($_SESSION['charge_id'])) { header('Location: index.php'); exit; } // 获取Charge详情 $charge = \Stripe\Charge::retrieve($_SESSION['charge_id']); unset($_SESSION['charge_id']); if ($charge->status === 'succeeded') { // 支付成功,更新数据库状态并跳转至成功页 // ... header('Location: payment_success.php'); } else { // 支付失败,跳转至失败页 $error = $charge->failure_message ?? '认证失败,请重试'; header('Location: payment_failed.php?error=' . urlencode($error)); }
内容的提问来源于stack exchange,提问作者Gandalf
相关产品推荐
相关产品推荐

