尤其是 macOS Catalina 版本开始的 Safari 浏览器,从系统层面支持通过 Apple 账户登录。用户只要一个指纹验证即可快速在网站或 App 上通过 Apple 账户 登录
准备
首先你需要准备一个 Apple 企业/个人 开发者账户,并访问 Certificates, Identifiers & Profiles 创建一个 AppId, ServiceId,生成授权私钥以及绑定可以用于和用户邮件沟通的邮件地址。
创建 App ID
Platform
选择 macOS,不可修改
Description
App 描述,可修改
Bundle ID
必须唯一,建议输入项目的域名,例如 domain.com
可以输入 com.domain
,不可修改
勾选 Sign In with Apple
选项
最后确认并注册,即成功创建 App 应用
创建 Services ID
在创建好 App ID
后,你还需要创建一个 Services ID
,用于管理和配置 Sign In with Apple
的安全域名、回调地址数据。
Description
服务描述,可修改
Identifier
服务标示,不可修改,建议输入项目接口域名,例如 api.domain.com
可以输入 com.domain.api
,不可修改
勾选 Sign In with Apple
并配置
Primary App ID
选择刚刚创建的 App ID
进行绑定
Web Domain
配置安全接口域名,例如 domain.com
,不需要 https 协议头
在设置完域名后,你可能需要对域名进行所有权验证,上传指定的文件到 https://domain.com/.well-known/apple-developer-domain-association.txt
Return URLs
授权登录后的接口回调地址,可配置多个
创建 Key
在授权登录时,我们需要效验并获取用户 access_token
等信息,这些信息需要通过 JWT 方式进行封装
Configure
中需要绑定刚刚创建的 App ID
在下载完毕后,你将会下载一个 .p8
的文件
配置邮箱
通过 Sign With in Apple
进行登录的用户,可以选择使用匿名的邮箱,如果你需要通过匿名邮箱与用户联系,你需要在这里授权绑定你的认证邮箱地址和域名
注意:邮箱地址必须通过 TLS 加密连接
准备就绪
当你完成上面所有内容后就开始开发了,以下是开发过程中会用到的数据,你可以先准备起来
teamId
十位数的企业/个人账户编号
clientId
刚刚注册的 Services ID
的 Identifier
scope
所需要获得的用户信息,以逗号分隔,可以有 openid,name,email
redirectURI
授权成功后的回调地址,需要与创建 Services ID
时候填写的地址匹配
privateKey
刚刚下载的 p8 文件
生成授权地址并授权
生成授权地址的方案有 2 种,一种是通过自己拼接授权地址,进行跳转打开,或者通过 Apple 提供的 appleid.auth.js
插件生成调用。
方案 1
地址格式如下
https://appleid.apple.com/auth/authorize?response_type=code& state=state&client_id=clientId&redirect_uri=redirectURI&scope=scope
state
自定义随机字符串,用于防止 CSRF 攻击
涉及到的参数需使用 URL Encode 编码进行处理
示例
const options = { response_type: code, // 固定内容 state: +new Date(), // 随机字符串,此处仅做演示 client_id: clientId, redirect_uri: redirectURI, scope: 'openid name email' } const url = new URL('https://appleid.apple.com/auth/authorize') const keys = Object.keys(options) keys.forEach(key => { url.searchParams.append(key, options[key]) }) // 输出内容 console.log(url.toString())
参考:Sign in with Apple REST API
方案 2(推荐)
Apple 提供的 Sign In with Apple JS
非常方便,并且你可以快速生成一个登录按钮
在页面引入这个 JS 文件,其中地址中的 en_US 可以更改为 zh-CN,以生成中文形式的按钮
<html> <head> <meta name="appleid-signin-client-id" content="[CLIENT_ID]"> <meta name="appleid-signin-scope" content="[SCOPES]"> <meta name="appleid-signin-redirect-uri" content="[REDIRECT_URI]"> <meta name="appleid-signin-state" content="[STATE]"> </head> <body> <div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div> <script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script> </body> </html>
如果你不想用 Apple 提供的按钮,想自定义按钮或触发方式,你可以直接使用 Sign In with Apple JS
中提供的方法
AppleID.auth.init({ clientId: 'clientId', scope: 'scope', redirectURI: 'redirectURI' }) // 调用这个方法将直接 运行 window.location.href 进行页面跳转 AppleID.auth.signIn()
授权登录
如果你使用的是 Safari 浏览器,那么在授权登录时会弹出系统层的授权登录窗口,否则将会跳转到 Apple 授权登录页面,所以它支持任何系统下的任何浏览器。
应用图标:这里的应用图标是灰色的,这是因为 Apple 暂时不支持纯 Web 使用的自定义图标,除非你以上面创建的 App ID 到 App Stroe 提交一个应用,这里将显示应用的图标。
invalid_request:通常这个问题是因为你的回调地址和 Apple 后台配置的地址不相同或还未生效,多尝试几次即可。
验证授权信息
获取信息
在授权后将会以 POST
方式传递授权信息到设置的回调地址中,数据包括 code
、id_token
、user#1
{ "code": "ccc9fe129dc0a...0k4W0aUqEA", "id_token": "eyJraWQiOiJBSURPUEsxIiwi...sb998sb0ZD-E5dJ9IQqXMSfR_5Q", "user": "{\"name\":{\"firstName\":\"测\",\"middleName\":\"\",\"lastName\":\"试\"},\"email\":\"[email protected]\"}" }
user:user 信息格式为 JSON,需要序列化后使用
获取 AccessToken
POST https://appleid.apple.com/auth/token
参考 Generate and validate tokens
主要解释一下 client_secret
参数的生成方法,Apple 数据通常都使用 JWT(JSON Web Tokens) 方式加密。使用算法为 ES256
// header const header = { alg: 'ES256', typ: 'JWT' } // payload const t = Math.floor(Date.now() / 1000) const payload = { iss: teamId, exp: t + 15777000, // 过期时间,六个月(最大) sub: clientId, aud: 'https://appleid.apple.com', iat: t // 精确到秒的时间戳 }
记得使用之前生成的 p8
格式的私钥进行数据加密
其他参数自行参考官方文档
// 回调内容 /** access_token: '', token_type: 'Bearer', expires_in: 3600, refresh_token: '', id_token: '' */
刷新授权 Token
你可以使用 refresh_token
对过期的 access_token
进行刷新#2
刷新 access_token
方式与验证授权方式大致相同,其中的 grant_type
值改为 refresh_token
并传递 refresh_token
参数
// 请求体 { client_id, client_secret, refresh_token, grant_type: 'refresh_token' }
验证数据并获得用户详细信息
接口返回的 id_token
中包含了用户授权的详细信息,需要通过 JWT 进行解密
在解密时,需要获取到 Apple 的 PublicKey,这个 Key 需要通过 GET https://appleid.apple.com/auth/keys
获取,你可以直接打开这个页面查看
const result = jwt.verify(id_token, PublicKey, { algorithms: 'RS256' }) // result /** { iss: 'https://appleid.apple.com', aud: 'com.domain', exp: 1571805905, iat: 1571805305, sub: '000598.189bb....9bb.0805', Apple用户标识符 at_hash: '55RTKN2v1Vy5K1r5JkWmSg', email: '[email protected]', email_verified: 'true', is_private_email: 'true', auth_time: 1571805303 } */
切记验证aud iss 等信息,防止伪造数据
重点关注
经过以上繁琐的步骤后,你现在可以正式上线这个项目了,不过你必须清楚以下信息
-
#1 在用户第一次授权登录时,你将会得到 用户信息,包括用户姓、名、中间名、邮箱地址,请务必保存它,因为只会在第一次登录时得到,之后的每次登陆将无法再获得。
-
#2 务必注意每天最多应只调用一次,多次调用可能被 Apple 限制访问。
AffiliateLabz
11:42 上午
Great content! Super high-quality! Keep it up! 🙂
hair growth oil
7:25 下午
Hi there, I found your web site via Google while looking for a related topic, your website came up, it looks good. I have bookmarked it in my google bookmarks
coconut oil for hair
7:19 下午
I am continuously searching online for posts that can help me. Thanks!
anyrepair
2:10 上午
很高兴了解在Apple中使用Sign with,网站配置Apple登录
Sign in with Apple – 微前端
9:19 上午
[…] 授权成功后的回调地址,需要与创建 Services ID 时候填写的地址匹配 […]