Apple ID 登录

news2024/11/25 0:30:05

Apple登录可以看做第三方登录的一种,即使用Apple ID登录,前提是你已经有了苹果开发者账号,直接进入主题吧。

添加App IDs
在这里插入图片描述
填写Bundle ID
在这里插入图片描述
勾选“Sign In with Apple”
在这里插入图片描述
创建Key
苹果将使用公钥/私钥对作为OAuth客户端机密,其中客户端机密实际上是一个签名的JWT,下一步需要向Apple注册新的私钥。
在这里插入图片描述
创建完成后会生成一个Key ID以及Key文件。下载key文件,其实就是一个.p8文件,双击可打开这个文件里面有需要的key,这个文件很重要,而且只能下载一次,请妥善保存!!!
在这里插入图片描述
在这里插入图片描述

生成客户端密钥(Client Secret)

苹果要求您自己从私钥中导出客户端密钥,而不是静态客户端密钥。他们使用JWT标准,使用带有P-256曲线和SHA256散列的椭圆曲线算法。换句话说,他们使用ES256JWT算法。有些JWT库不支持椭圆曲线方法,所以在开始尝试之前,请确保您的库支持椭圆曲线。RubyJWT库支持这种算法,因此我们将使用它来生成秘密。

首先,确保已安装Ruby,然后从命令行运行以下命令来安装JWT gem:

gem install jwt

根据上面准备的 Bundle IDTeam IDKey IDAuthKey_xxx.p8就可以生成client_secret(客户端密钥),我们简单创建一个txt文件,命名为secret_gen,然后将后缀改为.rb,即secret_gen.rb。模版内容如下:

require 'jwt'

key_file = ''
team_id = ''
client_id = ''
key_id = ''

ecdsa_key = OpenSSL::PKey::EC.new IO.read key_file

headers = {
  'kid' => key_id
}

claims = {
	'iss' => team_id,
	'iat' => Time.now.to_i,
	'exp' => Time.now.to_i + 86400*180,
	'aud' => 'https://appleid.apple.com',
	'sub' => client_id,
}

token = JWT.encode claims, ecdsa_key, 'ES256', headers

puts token

该代码使用ES256算法生成JWT,其中包含少量声明。JWT将在6个月内到期,这是苹果允许的最长使用期限。如果您在每次用户进行身份验证时都生成一个新的客户端密钥JWT,那么您应该使用更短的到期日期,但这允许我们生成一次密钥并在示例应用程序中轻松使用。

这里将用到我们已经准备好的四个数据,现在您可以从命令行运行它,它将输出一个JWT:
在这里插入图片描述

ruby xxx/xx/xx/secret_gen.rb

在这里插入图片描述
这个eyJra.....RuAQ就是我们需要的客户端密钥,接下来我们验证下这个密钥是否有效。

在项目中配置苹果登录

首先导入头文件#import <AuthenticationServices/AuthenticationServices.h>,然后调起苹果授权页面

    if (@available(iOS 13.0, *)) {

        ASAuthorizationAppleIDProvider *appleIdProvider = [[ASAuthorizationAppleIDProvider alloc] init];
        ASAuthorizationAppleIDRequest *authAppleIDRequest = [appleIdProvider createRequest];
        /*
         //慎用 ASAuthorizationPasswordRequest
         //当启用ASAuthorizationPasswordRequest且停止使用Apple ID(真机-设置-账户-密码与安全性-使用您Apple ID的App-App列表-停止使用 Apple ID, 如果KeyChain里面没有登录信息且重新使用苹果授权登录(Sign in with Apple)会报未知错误
         ASAuthorizationPasswordRequest* authPasswordRequest = [[[ASAuthorizationPasswordProvider alloc] init] createRequest];
         
         NSMutableArray <ASAuthorizationRequest*> * array = [NSMutableArray arrayWithCapacity:2];
         if(authAppleIDRequest) [array addObject:authAppleIDRequest];
         if(authPasswordRequest) [array addObject:authPasswordRequest];
         
         NSArray <ASAuthorizationRequest*> * requests = [array copy];
         ASAuthorizationController* authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:requests];
         */
        authAppleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
        
        //由ASAuthorizationAppleIDProvider创建的授权请求 管理授权请求的控制器
        ASAuthorizationController* authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[authAppleIDRequest]];
        //设置授权控制器通知授权请求的成功与失败的代理
        authorizationController.delegate = self;
        //设置提供 展示上下文的代理,在这个上下文中 系统可以展示授权界面给用户
        authorizationController.presentationContextProvider = self;
        //在控制器初始化期间启动授权流
        [authorizationController performRequests];
        
    } 

代理回调ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding

//授权成功
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0))
{
    NSString *userID = nil;
    NSString *userName = nil;
    NSString *userEmail = nil;
    
    EVAppleLoginCredentialModel *model = [[EVAppleLoginCredentialModel alloc] init];
    
    if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
        
        ASAuthorizationAppleIDCredential *credential = authorization.credential;
        
        //苹果用户唯一标识符,该值在同一个开发者账号下的所有App下是一样的,开发者可以用该唯一标识符与自己后台系统的账号体系绑定起来。
        userID = credential.user;
    
        //苹果用户信息 如果授权过,无法再次获取该信息
        userEmail = credential.email;
        NSPersonNameComponents *fullName = credential.fullName;
        userName = [NSString stringWithFormat:@"%@%@", fullName.familyName, fullName.givenName];
        
        //用于判断当前登录的苹果账号是否是一个真实用户,取值有:unsupported、unknown、likelyReal
        ASUserDetectionStatus realUserStatus = credential.realUserStatus;

        //服务器验证需要使用的参数
        NSString *authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding];
        NSString *identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding];
        
        NSLog(@"authorization [ASAuthorizationAppleIDCredential] successfully");
        NSLog(@"authorization userID: %@", userID);
        NSLog(@"authorization userName: %@", userName);
        NSLog(@"authorization userEmail: %@", userEmail);
        NSLog(@"authorization realUserStatus: %@", @(realUserStatus));
        NSLog(@"authorization authorizationCode: %@", authorizationCode);
        NSLog(@"authorization identityToken: %@", identityToken);
        
    } else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]) {
        //用户登录使用现有的密码凭证
        ASPasswordCredential *passwordCredential = authorization.credential;

        //密码凭证对象的用户标识 用户的唯一标识和密码
        userID = passwordCredential.user;
        NSString *password = passwordCredential.password;
    
        NSLog(@"authorization [ASPasswordCredential] successfully");
        NSLog(@"authorization userID: %@", userID);
        NSLog(@"authorization password: %@", password);
        
        model.user = passwordCredential.user;
        
        userName = @"";
        userEmail = @"";
        
    } else {
        assert(0);
    }
    
    //数据校验通过后,将这些数据发送给服务器进行验证,等待服务器的回应
    //如果用户选择隐藏邮箱的,email获取不到,其他数据正常,服务端匹配标准userID
    if (![ZJUtils isEmpty:userID]) {

        //在授权成功的回调中拿到服务器所需要的参数传给后台
        //至此我们所需要做的已经完成了,看后台的验证就行了
        if (self.appleLoginBlock) {
            self.appleLoginBlock(0, @"苹果授权成功", model);
        }
        
    } else {
        //授权数据异常
        if (self.appleLoginBlock) {
            self.appleLoginBlock(-1, @"苹果授权失败", nil);
        }
    }
}

//授权失败
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0))
{
    NSString *errorMsg = nil;
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    switch (error.code) {
        case ASAuthorizationErrorCanceled:
            errorMsg = @"用户取消了授权请求";
            break;
        case ASAuthorizationErrorFailed:
            errorMsg = @"授权请求失败";
            break;
        case ASAuthorizationErrorInvalidResponse:
            errorMsg = @"授权请求响应无效";
            break;
        case ASAuthorizationErrorNotHandled:
            errorMsg = @"未能处理授权请求";
            break;
        case ASAuthorizationErrorUnknown:
            errorMsg = @"授权请求失败未知原因";
            break;
    }
    NSLog(@"苹果授权状态:%@", errorMsg);
}

#pragma mark ASAuthorizationControllerPresentationContextProviding
- (ASPresentationAnchor) presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller API_AVAILABLE(ios(13.0))
{
    return self.view.window;
}

- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization 回调中我们拿到 authorizationCode 作为验证的参数。

打开postman我们测试下:

https://appleid.apple.com/auth/token?client_id=xxx&client_secret=xxx&code=xxx&grant_type=authorization_code&redirect_uri=https://appleid.apple.com

在这里插入图片描述

到这里就基本完成了,其实苹果登录大部分工作都是后台在做,包括client_secret生成等,我们客户端只需要在拿到苹果授权的数据给后端就可以了,后端去做校验。

参考:What the Heck is Sign In with Apple?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/43118.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【mongodb】重新整理mongodb中的各种操作

目录前言初始化封装基础方法增&#xff1a;向集合内添加一个文档增&#xff1a;向集合内一次添加多条文档删&#xff1a;删除一条文档删&#xff1a;删除多条文档删&#xff1a;清空某个集合的所有文档查&#xff1a;查询符合条件的文档查询某个集合内所有文档&#xff1a;定位…

python>>numpy(第二讲)

章节内容 元素操作 常用的方法 广播 数组形状操作 排序数组 目录 元素操作 一些常用的方法 广播 数组形状操作 数组排序 元素操作 生成元素a np.array([1,2,3,4]) b np.ones(4)1 生成一个原来数组的n倍生成一个所有元素均跟2次方有关的数组一个计算矩阵相乘的函数判断两个…

<Android开发> HAL层集成第三方so库

当我们需要在自己的代码中使用第三方提供的一些接口函数时&#xff0c;我们该如何加入&#xff1f;作者在写这比安文章前遇到了一个问题&#xff1a;需要在自己的HAL层中引用第三饭提供的算法库即so库&#xff1b;这个问题是作者第一次遇到&#xff0c;以往都是自己写一些代码编…

原宇宙之地产探索

前言 随着“元宇宙”的概念风靡全球&#xff0c;一股“炒房”之风也开始在元宇宙世界兴起&#xff0c;就连大家熟知的歌手林俊杰、Snoop Dogg也纷纷入局元宇宙。昂贵的元宇宙房价有些甚至高于北京的一套别墅价格。 元宇宙中的“炒房” 去年下半年&#xff0c;元宇宙房地产玩家竞…

Android Compose Bloom 项目实战 (二) : 欢迎页

1. 前言 上一篇文章我们讲到了Compose Bloom项目开发之前的一些配置及沉浸式状态栏的修改。 这篇文章接着上文&#xff0c;会介绍欢迎页的开发。 需要实现的页面效果如下所示 2. 分析页面组件 根据UI图&#xff0c;我们可以可知&#xff0c;该页面是由背景和前面部分部分组…

IDEA配置tomcat,快速部署tomcat

Tomcat简介 Tomcat是Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的Jakarta 项目中的一个核心项目&#xff0c;由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持&#xff0c;最新的Servlet 和JSP 规范总是能在Tomcat 中得…

地震数据处理研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Kubernetes集群coredns缓存容器bind: address already in use错误导致集群服务无法互通解决

coredns缓存nodelocal dns cache :53: bind: address already in use错误处理起因分析问题处理问题重启Node local dns起因 事情起因是Kubernetes集群内的服务无法互相访问了 分析问题 因为Kubernetes集群内的服务都是通过service、pod的名称作为域名到coredns解析Cluster I…

ubuntu 18.04安装python3.7.5,并将 python 设定为python3, pip设定为pip3

ubuntu 18.04安装python3.7.5&#xff0c;并将 python 设定为python3&#xff0c; pip设定为pip3环境&#xff1a;Ubuntu 18.04.1安装步骤&#xff1a;一、安装python3.7二、安装pip3三、更改python为 python3指向&#xff0c;更改pip为pip3指向四、注意点&#xff0c;必须改回…

基于java+ssm+easyui灵悟酒店系统

✌博主介绍✌:一个致力于全战开发的代码热爱者 基于javassmeasyui灵悟酒店系统一、前言介绍&#xff1a;二、系统设计&#xff1a;2.1 系统整体架构&#xff1a;2.2 系统功能设计&#xff1a;三、功能截图&#xff1a;3.1 首页&#xff1a;3.2 用户登陆&#xff1a;3.2.1 登陆后…

【Android App】三维处理中三维投影OpenGL功能的讲解及实战(附源码和演示 超详细必看)

运行有问题或需要源码请点赞关注收藏后评论区留言~~~ 一、OpenGL的讲解 OpenGL定义了一个跨语言&#xff0c;跨平台的图形程序接口&#xff0c;对Android开发者来说&#xff0c;OpenGL就是用来绘制三维图形的技术手段&#xff0c;当然OpenGL不仅仅能够展现静止的三维图形&…

深入理解地址翻译 CSAPP

地址翻译, 用自己的话说一遍, 然后自己在draw.io画图理解. 术语 页表就是一个 页表条目&#xff08;Page Table Entry PTE)的数组&#xff0c;每一项(每个PTE)是[有效位&#xff0c;物理地址]. 我们是用VPN来标识每个PTE,但记住这些VPN并不是页表的一部分&#xff0c;不会储…

基础知识——进制 与 进制转换 (C++ 程序)

目录 一、进制的定义 二、表示方法 1、当进制数 ≤ 10时 2、当进制数&#xff1e;10时 三、进制的计算 1、整数 2、小数 3、非十进制数 4、非十进制转十进制 四、十进制转非十进制数 1、整数部分 2、小数部分 3、整小混合 五、程序实现 1、十进制 转 其它进制 …

Unity 3D 动画系统(Mecanim)|| Unity 3D 人形角色动画(Avatar)

Unity 3D 动画系统&#xff08;Mecanim&#xff09; Mecanim 动画系统是 Unity 公司推出的全新动画系统&#xff0c;具有重定向、可融合等诸多新特性&#xff0c;可以帮助程序设计人员通过和美工人员的配合快速设计出角色动画&#xff0c;其主界面如下图所示。 Unity 公司计划…

wy的leetcode刷题记录_Day50

wy的leetcode刷题记录_Day50 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2022-11-23 前言 补 目录wy的leetcode刷题记录_Day50声明前言1742. 盒子中小球的最大数量题目介绍思路代码收获700. 二叉搜索树中的搜索题目介绍思路代码收获…

Maven问题相关 1 存在jar 却无法映射

这是一个比较新手的问题了&#xff0c;可能刚接触这个问题的小伙伴会纳闷&#xff0c;我这个本地仓库明明有却怎么映射失败吗?不科学啊。尤其是面临公司项目很多依赖的情况下&#xff0c;会出现大量这种情况&#xff0c;就算是项目经理过来。也可能会卧槽&#xff0c;我电脑上…

基于python的CLI应用程序开发(第一节):简单了解一下Typer

Typer开发(第一节)&#xff1a;简单了解一下Typer 文章目录Typer开发(第一节)&#xff1a;简单了解一下Typer1. 简介2. 安装3. 在编辑器中使用Typer4. 简单应用15. 简单应用26. 命令参数7.其它1. 简介 Typer 是一个python用于构建 CLI 应用程序的库,简单说就是开发控制台程序&…

Idea+maven+spring-cloud项目搭建系列--8整合Zookeeper

本文为 Ideamavenspring-cloud项目搭建系列&#xff0c;maven项目的创建可以参考&#xff1a; https://blog.csdn.net/l123lgx/article/details/121467823 本文使用了nacos 作为微服务的注册与发现&#xff0c;nacos 阿里云服务器的安装可以参考&#xff1a;https://blog.csdn.…

构建用于签名/加密双证书测试体系的可执行命令

注意事项 生成证书请求的填写 范例Subject: C CN, ST Beijing, L Beijing, O MSI, OU msi, CN ca, emailAddress cagmssl.com 前面的步骤存在错误&#xff0c;后面改用脚本进行证书生成&#xff0c;阅读时请跳过前面错误的内容 错误的内容 -> 开始 CA 生成私钥 op…

了解mysql脏页落盘过程

脏页落盘 什么是脏页&#xff1f; 对数据的修改&#xff0c;首先改内存中的缓冲池的页&#xff0c;由于缓冲区的数据跟磁盘中的数据不一致&#xff0c;所以称缓冲区的页为脏页。 脏页如何写入到磁盘&#xff1f; 不是每次更新都触发脏页落盘&#xff0c;而是通过CheckPoint机…