开发日记 —— 记录对接苹果登录的坑

来源: 超级浩码

最近在开发新项目时用到了 苹果登录、微信登录和订阅支付,由于是第一次对接以上内容,踩了不少坑,记录一下。

本文主要介绍苹果登录,我也会在之后的文章中介绍微信登录和订阅支付。

前言

之前我的APP中大多数是买断式的,用户可以使用一些基本的功能,如果需要高级功能,则需要付费买断。

这次介于新的项目的特点,我决定在买断的基础之外加上订阅支付,对我来说算是一种新的尝试吧。有了订阅同时也就意味着需要构建一个用户体系来管理订阅。

对于订阅支付来说用户体系更符合逻辑。但在调研过程中也发现有些APP没有做登录(用户体系)也依然有订阅支付,其主要还是依靠大部分IAP组件提供的恢复购买功能+本地验证接口实现的。但是这里面还是有一些坑,在下文会介绍。

正文

先看下完整的苹果登录流程:

500

1. 苹果开发者后台配置

服务端需要的参数,可在苹果开发者后台设置。设置App ID, 在 Capabilities 中设置 Sign In with Apple

500

500

创建一个用来在服务端与Apple服务器交互的Key,并下载密钥文件。

500

500

2. 客户端配置

选择主流的Apple登录插件Sign_in_with_apple。

500

dependencies:  flutter:    sdk: flutter  sign_in_with_apple: ^latest_version

在登录按钮里调用方法:

final credential = await SignInWithApple.getAppleIDCredential(                    scopes: [                      AppleIDAuthorizationScopes.email,                      AppleIDAuthorizationScopes.fullName,                    ],                  );

返回结果credential的结构如下源码:

/// Authorization details from a successful Sign in with Apple flow.////// Most fields are optional in this class.////// Especially [givenName], [familyName], and [email] member will only be provided on the first authorization between/// the app and Apple ID.////// The [authorizationCode] member is always present and should be used to check the authorizations with Apple servers/// from your backend. Upon successful validation, you should create a session in your system for the current user,/// or consider her now logged in.@immutableclass AuthorizationCredentialAppleID {  /// Creates an instance which contains the result of a successful Sign in with Apple flow.  const AuthorizationCredentialAppleID({    // 略...  });  // 略...  /// An identifier associated with the authenticated user.  ///  /// This will always be provided on iOS and macOS systems. On Android, however, this will not be present.  /// This will stay the same between sign ins, until the user deauthorizes your App.  final String? userIdentifier;  /// The verification code for the current authorization.  ///  /// This code should be used by your server component to validate the authorization with Apple within 5 minutes upon receiving it.  final String authorizationCode;  /// A JSON Web Token (JWT) that securely communicates information about the user to your app.  final String? identityToken;  // 略...}

我们主要用到的是这样几个字段:

userIdentifier —— 苹果用户的唯一标识

identityToken —— jwt加密的idToken,可以在通过接口获取出上面的userIdentifier

authorizationCode —— 配合secret,keyId,teamId,clientId可以获取到jwt加密的idToken

PS: userIdentifier 是用户唯一标识, 如果没有服务端则可以通过 userIdentifier 直接使用但不推荐。正确安全的方式通过服务端获取,就可以用第二或第三个字段。服务端代码可参考这里:go-signin-with-apple。

3. XCode配置

打开ios目录,在Runner(文件浏览器侧栏)-> Targets-> Runner->Signing & Capabilities设置 Apple Developer Portal 中创建的“Bundle Identifier”

500

确保应用具有“使用 Apple 登录”功能(Runner(文件浏览器侧边栏)-> Targets-> Runner-> Signing & Capabilities),否则使用 Apple 登录将失败且没有视觉指示(代码仍会收到异常) )

500

4. 服务端验证

通过 authorizationCode 获取 userIdentifier

import "github.com/Timothylock/go-signin-with-apple/apple"client := apple.New()vReq := apple.AppValidationTokenRequest{ ClientID:     clientID, ClientSecret: secret, Code:         "authorizationCode", // 客户端获取的 authorizationCode}var resp apple.ValidationResponse// Do the verificationclient.VerifyAppToken(context.Background(), vReq, &resp)unique, _ := apple.GetUniqueID(resp.IDToken)// Voila!fmt.Println(unique)

通过 identityToken 获取 userIdentifier

unique, _ := apple.GetUniqueID(params.IDToken)claim, _ := apple.GetClaims(params.IDToken)

解析后,claim["sub"]是userIdentifier, claim[aud]是BundleID。

最后,将userIdentifier和token保存到数据库中,以上是苹果登录的配置和流程。

发表于河南省
2024-03-31
科技

观察者APP,更好阅读体验

乌方最终宣称命中41架俄军机,俄方怎么说?

“特朗普敲竹杠,中国不吃这套”

美大学藏“中国间谍”?CIA前官员都看不下去了

卫星图显示:13架俄大型机遭摧毁,包括8架图95

尹志尧的“并购术”:中国半导体设备平台化突围利器