我正在构建一个网络应用程序,允许我们的用户出售音乐表演的门票。为了处理购票者和演出发起人之间的付款,我使用了 Stripe。 基本上,节目发起者在我的应用程序上创建他的节目页面,用户可以购买该节目的门票。
为了创建一场演出,发起人需要填写一份表格(演出名称、演出日期、演出地点、演出乐队等)。该表格还要求演出发起人提供他的可发布和秘密条纹钥匙。我的应用程序使用这两个令牌来检索信用卡信息(在客户端)并处理付款(在服务器端)。
问题是,我想确保显示煽动者提供有效且现有的 Stripe 键。我不希望我的用户因为表演发起者没有提供有效的 Stripe 密钥而偶然发现付款错误。
所以,我的问题是: 如何验证可发布密钥和秘密密钥是否有效且存在?实现这一目标的最佳策略是什么?谢谢!
明白了!
要验证您的可发布密钥,您需要使用 cURL 向 stripe 请求新令牌。 如果给定的密钥无效,响应将包含一条以 “提供的 API 密钥无效”开头的错误消息。
这是用 PHP 编写的示例:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.stripe.com/v1/tokens");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "card[number]=4242424242424242&card[exp_month]=12&card[exp_year]=2017&card[cvc]=123");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_USERPWD, $publishableKey . ":");
$response = json_decode(curl_exec($ch),true);
if( curl_errno($ch) ){
echo 'Error:' . curl_error($ch);
}
curl_close ($ch);
if(substr($response["error"]["message"],0, 24 ) == "Invalid API Key provided"){
echo "Invalid API Key provided";
}
验证密钥的想法相同。
但是对于公钥......我找到了一种使用 Stripe.js 的方法:
let stripe = Stripe( <public key to test> );
setTimeout( ()=>{
stripe.createToken('pii', {personal_id_number: 'test'})
.then( result =>{
if( result.token )
// public key is valid :o)
else
// nope !
})
}, 300 )
注意调用 stripe.createToken() 之前的超时。 如果你不这样做,createToken() 返回的 Promise 将永远不会回来。
更新:刚刚收到 Stripe 的确认;这是一个有效且可接受的方法。
要求您的合作伙伴提供有效的信用卡,并告知他们,为了验证他们的 Stripe 密钥,您将向他们的卡收取 0.50 美元的费用,该费用将立即退还。
作为表单验证的一部分,当给出两个密钥时,
提交一个隐藏表单,其中包含创建卡令牌所需的所有数据。您应该能够检查创建卡令牌响应处理程序中的响应并确定可发布密钥是否有效。
如果您从条带服务器收到包含卡令牌的成功响应,请右转并提交测试费用,费用为 0.50 美元(最低费用金额)。
确保您正确捕获所有条纹异常。我相信如果密钥无效,您应该捕获Stripe_InvalidRequestError。如果抛出异常,您可以向用户报告。
如果没有出现错误,将进行收费。由于您不想向合作伙伴收取费用,因此您需要从条带响应中捕获费用 ID 并立即退还费用。
这是一个 PHP 示例:
try {
\Stripe\Stripe::setApiKey($secret_key);
// create a test customer to see if the provided secret key is valid
$response = \Stripe\Customer::create(["description" => "Test Customer - Validate Secret Key"]);
return true;
}
// error will be thrown when provided secret key is not valid
catch (\Stripe\Error\InvalidRequest $e) {
// Invalid parameters were supplied to Stripe's API
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
catch (\Stripe\Error\Authentication $e) {
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
catch (\Stripe\Error\ApiConnection $e) {
// Network communication with Stripe failed
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
catch (\Stripe\Error\Base $e) {
// Display a very generic error to the user, and maybe send
// yourself an email
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script>
Stripe.setPublishableKey('{{FILL_THIS_WITH_YOURS}}');
Stripe.createToken({}, function(status, response) {
if (status == 401) {
//invalid public key
} else {
//valid public key
}
});
</script>
然后如果密钥有效,您可以使用ajax发送表单并使用同一系统验证密钥服务器端。
$('body').on('submit', '.stripe_validate_keys', function(e){
e.preventDefault();
//public key submitted by your form
var public_key = $('.stripe_validate_keys').find('input[name="ba_stripe_public"]').val();
stripe = Stripe( public_key, {
betas: ['payment_intent_beta_3']
});
//Trying to retrieve a customer who don't exist
//You have to pass only the prefix
stripe.retrieveSource({
id: 'src_',
client_secret: 'src_client_secret_',
})
.then(function(result) {
var res = result.error.message;
var test = res.search( 'Invalid API Key' );
if( test === 0 ){
//Key invalid
} else {
//Now you can submit your form for validate secret key server side
}
});
});
可发布密钥
从这个普通的 JS 答案扩展:
import {loadStripe} from '@stripe/stripe-js';
...
/**
* Validate the public key
*
* @param value
* @returns {Promise<string>}
*/
async validatePublicKey(value)
{
//must start with pk_
if (!/^pk_/.test(value))
return 'Public key must start with pk_';
//Test that Stripe accepts the key
//Init Stripe JS
let stripe = await loadStripe(value);
let {token, error} = await stripe.createToken('pii', {personal_id_number: 'test'});
if (error)
return error?.message ?? 'Invalid public key';
}
正如其他人提到的,Stripe 表示这是验证可发布密钥的可接受的方法。秘钥
/**
* Check if a given string is a valid stripe secret key by attempting to make a request to the stripe API
*
* @param string $key
* @return bool
* @throws \Stripe\Exception\ApiErrorException
*/
function validateSecretKey(string $key): bool
{
if (!str_starts_with($key, 'sk_'))
return false;
//Instantiate the stripe client with the key that needs validating
$client = new \Stripe\StripeClient([
"api_key" => $key
]);
try
{
//Attempt to create a pii token
$client->tokens->create(["pii" => ["personal_id_number" => "test"]]);
}
catch (\Stripe\Exception\AuthenticationException)
{
//If the key is invalid, stripe will throw an authentication exception
return false;
}
return true;
}