Sign in with Apple
Provide users the ability to sign in to your apps and websites using their Apple ID.
Overview
Sign in with Apple gives your users a fast and safe way to sign in to your apps and websites using their Apple ID. Incorporating Sign in with Apple eliminates the need for additional sign-up steps, allowing users to engage and focus on your app or website.
To support Sign in with Apple for websites, you must integrate Sign in with Apple JS. Use the Sign in with Apple REST API to communicate with Apple servers. For native iOS, macOS, tvOS, and watchOS apps, use the AuthenticationServices framework.
简介
Sign In with Apple
登录支持的最低iOS系统要求是iOS13,凡是包含第三方登录功能的App,必须带有苹果登录功能,且样式需要满足苹果要求,并需要把苹果登录放在所有第三方登录的前面,也就是说要放在第一个位置上,上架应用被要求添加苹果登录功能的最终截止时间不详。不过可以肯定的是,在7月30日我提交了审核,8月1日被拒了,原因就是没有添加苹果登录功能。
苹果提供文档之Implementing User Authentication with Sign in with Apple
苹果提供文档之Sign in with Apple
苹果提供文档之Human Interface Guidelines
实现
- 1、登录苹果开发者后台,把需要添加苹果登录的
Identifiers
的项目打开登录开关
保存后,下载.p8文件,文件下载完要保存好,因为只提供一次下载机会。
- 2、添加key
添加完可以直接在下面的页面看到keyID和teamID,都复制一下,后面需要用到
- 3、打开项目,按照下图中1、2步添加
Sign In with Apple
- 4、到登录页面添加代码
导入系统头文件#import
实现两个代理方法ASAuthorizationControllerDelegate
和ASAuthorizationControllerPresentationContextProviding
添加苹果登录按钮,按钮ASAuthorizationAppleIDButton
是系统提供的,只要实现了两个代理就能轻松获取登录用户的信息,代码如下:
按钮布局
if (@available(iOS 13.0, *)) {
ASAuthorizationAppleIDButton *appleButon = [[ASAuthorizationAppleIDButton alloc]initWithAuthorizationButtonType:ASAuthorizationAppleIDButtonTypeSignIn authorizationButtonStyle:ASAuthorizationAppleIDButtonStyleBlack];
appleButon.cornerRadius = 30.f;
[appleButon addTarget:self action:@selector(appleSignAction) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:appleButon];
[appleButon mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.right.mas_equalTo(0);
make.height.mas_equalTo(view.mas_width);
}];
}
代理方法
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization NS_SWIFT_NAME(authorizationController(controller:didCompleteWithAuthorization:)) API_AVAILABLE(ios(13.0)){
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential *credential = authorization.credential;
NSLog(@"credential = %@",credential);
NSString *state = credential.state;
NSString *userID = credential.user;
NSPersonNameComponents *fullName = credential.fullName;
NSString *email = credential.email;
NSString *authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding]; // 验证 token
NSString *identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding]; // 用户 token
ASUserDetectionStatus realUserStatus = credential.realUserStatus;
NSArray *authorizedScopes = credential.authorizedScopes;
NSLog(@"state: %@\nuserID: %@\nfullName: %@\nemail: %@\nauthorizationCode: %@\nidentityToken: %@\nrealUserStatus: %@\nauthorizedScopes: %@",
state,
userID,
fullName,
email,
authorizationCode,
identityToken,
@(realUserStatus),
authorizedScopes);
}
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error NS_SWIFT_NAME(authorizationController(controller:didCompleteWithError:)) API_AVAILABLE(ios(13.0)){
NSString *errorMsg = nil;
switch (error.code) {
case ASAuthorizationErrorCanceled:
errorMsg = @"用户取消了授权请求";
break;
case ASAuthorizationErrorFailed:
errorMsg = @"授权请求失败";
break;
case ASAuthorizationErrorInvalidResponse:
errorMsg = @"授权请求响应无效";
break;
case ASAuthorizationErrorNotHandled:
errorMsg = @"未能处理授权请求";
break;
case ASAuthorizationErrorUnknown:
errorMsg = @"授权请求失败未知原因";
break;
}
}
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0)){
return self.window;
}
-(void)appleSignAction{
if (@available(iOS 13.0, *)) {
ASAuthorizationAppleIDProvider *provider = [[ASAuthorizationAppleIDProvider alloc] init];
ASAuthorizationAppleIDRequest *request = [provider createRequest];
request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
ASAuthorizationController *vc = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
vc.delegate = self;
vc.presentationContextProvider = self;
[vc performRequests];
}
}
后端验证
1、前端获取到
Apple ID
的用户信息后,需要把code
传给后端,后端再调用苹果的验证接口进行验证,通过验证接口返回的数据进行校验(此处省略一万字
)...code
是什么呢?code
就是前端获取到的authorizationCode
2、苹果验证接口:
https://appleid.apple.com/auth/token
必传参数
client_id:app的 bundle identifier
code:手机端获取到的 authorizationCode
grant_type:传入固定字符串 authorization_code
client_secret:秘钥
- 3、秘钥client_secret的生成
使用ruby
代码生成client_secret,对于ruby
应该不会陌生,就算ruby
代码不会写(我也不会写,代码是copy的)
,至少也知道这个东西,毕竟使用pod
管理代码的前提是必须安装ruby
环境
ruby
代码如下:
require "jwt"
key_file = "Path to the private key"
team_id = "Your Team ID"
client_id = "Your App Bundle ID"
key_id = "The Key ID of the private key"
validity_period = 180 # In days. Max 180 (6 months) according to Apple docs.
private_key = OpenSSL::PKey::EC.new IO.read key_file
token = JWT.encode(
{
iss: team_id,
iat: Time.now.to_i,
exp: Time.now.to_i + 86400 * validity_period,
aud: "https://appleid.apple.com",
sub: client_id
},
private_key,
"ES256",
header_fields=
{
kid: key_id
}
)
puts token
参数说明
key_file:苹果开发者中心下载的.p8文件
(实现-1步骤中提到的)
保存的路径
team_id:开发者账号的teamID(实现-2步骤中提到的)
client_id:项目的bundleID
key_id:苹果开发者中心创建的keyID(实现-2步骤中提到的)
在上面的ruby
中,有看到引入jwt
,那么还需要你的Mac安装jwt
环境。
打开终端,输入命令:sudo gem install jwt
安装jwt
环境,安装完成后,桌面创建一个文件夹,并在终端cd到该文件目录下,然后输入命令:touch secret_gen.rb
创建.rb
文件,创建完成双击打开该文件,把上面的ruby
代码复制黏贴进去,并修改key_file、team_id、client_id、key_id这四个key的value,保存文件,秘钥client_secret就生成了。
其实client_secret大可不必由前端来生成,完全可以由后端同事自己去搞,奈何实在是太想装逼的我想要嘚瑟一把(此处省略一万字)
...
好了,到此为止,后端完成了苹果的验证之后,后续业务该怎么玩怎么玩了,其实关于Sign In with Apple
登录的文章一搜一大把,说来说去主要重点就是这么点东西,可能部分细节我这里没有实现,但是重点就是这些。
全剧终
2020-8-26 补充 Apple登录成功案例之一
(深沉厚重的背景独白,自己配音)
事情发生在2020年7月30号的早上7点09分,还记得那是第一次因为Apple登录的问题被苹果拒绝审核通过……刹那间,仿佛过了许多个日日夜夜……咳咳,不扯淡了,哈哈哈哈
- 时间是7月30号第一次被拒,原因是未添加Apple第三方登录,由于是初次实现该功能,所以用的时间比较长吧,到了8月4号,已经完全实现了Apple登录功能,只不过需要和后台对接的相关处理还没搞定,也是因为后台的功能还没有实现,呵!垃圾……
不小心暴露了上班时间,好吧,我们公司是6.30下班的
- 页面显示
看到了吧,登录页面就是上面这个样子的了
登录成功后需要用户补充邮箱和手机号码
最后的提审时间是8月25号上午11点46分
8月25号晚上23点45分通过审核