前言

之前写过一篇Stripe的信用卡支付的接入文章,这篇文章是由于前两天突然看到Stripe官网上,有这样的提醒,所以我们及时更新了客户端和服务器的API。

SCA提示

在2019年9月,新的欧洲法规将开始要求从欧洲客户到欧洲企业的许多在线支付的强客户认证(SCA)。受影响的企业需要在结账时提供额外的身份验证层,以帮助保护客户的安全。 Payment Intents API完全支持SCA(包括免除逻辑),并确保您仅在严格要求时要求客户提供其他身份验证。 其实就是说之前的支付API在今年九月份就不能用了,赶紧使用新的Payment Intents API来接入支付吧。

Payment Intents API的两种接入方式对比:Automatic Confirmation 和 Manual Confirmation

Payment Intents两种接入方式

以上是Stripe 官方对这两种接入方式的对比图,大致解释一下重点吧,

  1. Automatic Confirmation(自动确认)是最简单的方式从零接入Payment Intents API , 而Manual Confirmation(手动确认)是最简单的方式把Charges API迁移到当前的API。(就是说用了之前API的人可以采用手动确认方式修改快,而从零开始就用自动确认方式接入快)

  2. Automatic Confirmation是在支付成功后通过webhooks异步处理,Manual Confirmation是同步处理的需要等服务器支付成功再返回。意思就是自动确认是在客户端确认的,省去了服务器在支付成功后的一系列对数据库或其他等操作的等待时间。

  3. Stripe处理类似3D Secure 2等身份验证流程的UI。这里两种方式是一样的。

  4. Automatic Confirmation 是整合一次可以更容易的处理所有的支付方式并且只有很小的UI改动,而Manual Confirmation是需要进行很大的改动去接入非信用卡支付的其他支付方式。

  5. 使用Automatic Confirmation服务器往返次数会更少,因为在前端可以做Stripe验证。而Manual Confirmation 在需要验证的时候,会有额外的服务器往返次数。

所以在对比了之后,我们还是选择了自动确认方式进行接入,因为毕竟我们是要接入很多其他支付方式的。

Automatic confirmation 和 Manual Confirmation流程介绍

Automatic confirmation流程

Automatic confirmation流程图

  1. 在服务器创建PaymentIntent

  2. 把PaymentIntent的密钥client secret发给客户端

  3. 在客户端收集信用卡的详细信息

  4. 在客户端向Stripe提交支付

  5. 在服务器异步接收到创建成功的消息后,填充客户的订单等信息,操作数据库等

Manual confirmation流程

Manual confirmation流程图

  1. 在客户端收集信用卡的详细信息

  2. 在服务器创建PaymentIntent

  3. 在客户端处理下一步的动作

  4. 又在服务器确认PaymentIntent

iOS端接入Automatic confirmation

1. 首先是把通过接口把付款的金额和付款的货币发给自己的服务器,服务器创建Payment Intents,然后把ClientSecret 返回给客户端

####2. 收集卡的信息并进行支付操作,我这里直接写在一起了,下面的方法是可以支持 3D Secure 2身份验证的,(Stripe 版本 16.0.1)如下面的代码所示:(关于什么是3D Secure 2验证,可以查询资料,简单解释就是在信用卡付款的时候,如果信用卡开通了这个服务,发卡机构还会需要用户再确认一次确保安全)

//首先要实现 STPAuthenticationContext 协议


//发起stripe支付
-(void)stripePay{
//我这里是直接使用Stripe自带的STPPaymentCardTextField收集的卡参数
    STPPaymentMethodParams *paymentMethodParams = [STPPaymentMethodParams paramsWithCard:self.paymentTextField.cardParams billingDetails:nil metadata:nil];
//服务器传递过来的ClientSecret
    STPPaymentIntentParams *paymentIntentParams = [[STPPaymentIntentParams alloc] initWithClientSecret:self.viewModel.clientSecret];
    paymentIntentParams.paymentMethodParams = paymentMethodParams;
    // paymentIntentParams.savePaymentMethod = @YES;
    //自己设置的urlScheme: your-app://stripe-redirect
    //paymentIntentParams.returnURL = @"xxx://xxx.stripe.com";
    [[STPPaymentHandler sharedHandler] confirmPayment:paymentIntentParams
                            withAuthenticationContext:self
                                           completion:^(STPPaymentHandlerActionStatus handlerStatus, STPPaymentIntent * handledIntent, NSError * _Nullable handlerError) {
                                               @strongify(self)
                                               [MBProgressHUD mh_hideHUDForView:self.view];
                                               switch (handlerStatus) {
                                                   case STPPaymentHandlerActionStatusFailed:
                                                       // 支付失败
                                                       [NSObject mh_showAlertViewWithTitle:SDLocalized(@"paymentFailed", nil) message:handlerError.localizedDescription] confirmTitle:SDLocalized(@"ok", nil)];
                                                       //                                                             NSLog(@"error:%@",error.userInfo);
                                                       break;
                                                   case STPPaymentHandlerActionStatusCanceled:
                                                        //取消支付
                                                       break;
                                                   case STPPaymentHandlerActionStatusSucceeded:
                                                       //支付成功                                                      
                                                       self.viewModel.isPaySuccess = YES;
                                                       break;
                                               }
                                           }];
复制代码

然后后台服务器的webhock会收到是否支付成功的信息,然后做一些相应的处理。

这是3D Secure 2 的界面截图,在输入信用卡信息,点击支付后,如果信用卡已开启3D Secure 2服务,则会跳转到这里再确认一次。

Stripe提供的开启了3D Secure 2服务的测试信用卡号(我这里列举2个): 4000 0000 0000 3220 4000 0000 0000 3063(这个卡号可以测试验证失败的回调)

以上就是Automatic confirmation接入的iOS端的实现方式及代码。

iOS端接入Manual confirmation (这里我没修改成支持3D Secure 2验证的代码,最近比较忙,有空再加,可以看官方Github的demo)

使用这种接入方式,我们iOS端需要做的事就相对而言少一些了,因为是在服务端进行验证的。

STPPaymentMethodParams *paymentMethodParams = [STPPaymentMethodParams paramsWithCard:self.paymentTextField.cardParams billingDetails:nil metadata:nil]; [[STPAPIClient sharedClient] createPaymentMethodWithParams:paymentMethodParams completion:^(STPPaymentMethod * _Nullable paymentMethod, NSError * _Nullable error) { //调用接口把stripeId发送给服务器 // paymentMethod.stripeId; }];


    }];
    if (self.redirectContext) {
        // opens SFSafariViewController to the necessary URL
        [self.redirectContext startRedirectFlowFromViewController:self];
    } else {
        // This PaymentIntent action is not yet supported by the SDK.
    }
} else {
    // Show success message
}
复制代码

同样的需要设置以下的delegate,用来跳转到验证的URL,代码如下所示

// This method handles opening native URLs (e.g., "your-app://")
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    BOOL stripeHandled = [Stripe handleStripeURLCallbackWithURL:url];
    if (stripeHandled) {
        return YES;
    } else {
        // This was not a stripe url – do whatever url handling your app
        // normally does, if any.
    }
    return NO;
}

// This method handles opening universal link URLs (e.g., "https://example.com/stripe_ios_callback")
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
    if (userActivity.activityType == NSUserActivityTypeBrowsingWeb) {
        if (userActivity.webpageURL) {
            BOOL stripeHandled = [Stripe handleStripeURLCallbackWithURL:url];
            if (stripeHandled) {
                return YES;
            } else {
                // This was not a stripe url – do whatever url handling your app
                // normally does, if any.
            }
            return NO;
        }
    }
}
复制代码

4.还需要在服务器里服务器里再次确认一下PaymentIntent,完成支付并且填充订单,做一些数据库操作等。

期待

  • 以上就是关于Stripe官方配合欧洲SCA准备的PaymentIntent API的两种接入方式的详解

  • 文章若有些许帮助,请给个喜欢或评论;若没啥帮助,请给点建议~

  • 如果有疑问,请在文章底部评论指出,我会火速解决和修正问题。