EN

Apple 登录配置

本指南介绍如何配置 Sign in with Apple,为用户提供安全、注重隐私的登录方式。

前置条件

步骤 1:创建 App ID

  1. 打开 Apple Developer Portal
  2. 进入 Certificates, Identifiers & Profiles
  3. 点击侧边栏 Identifiers
  4. 点击 + 添加新标识符
  5. 选择 App IDs,点击 Continue
  6. 选择 App 类型,点击 Continue
  7. 填写信息:
  • Description:您的应用名称
  • Bundle ID:显式(如 com.yourcompany.myapp
  1. Capabilities 中启用 Sign in with Apple
  2. 点击 Continue,然后 Register

步骤 2:创建 Services ID(Web 用)

Web 应用需要创建 Services ID:

  1. 进入 Identifiers
  2. 点击 +,选择 Services IDs
  3. 点击 Continue
  4. 填写信息:
  • Description:"MyApp Web Login"
  • Identifier:com.yourcompany.myapp.web
  1. 点击 Continue,然后 Register

配置 Web 认证

  1. 在列表中找到您的 Services ID 并点击
  2. 启用 Sign in with Apple
  3. 点击 Configure
  4. 配置 Web 认证:
字段
Primary App ID 您的主 App ID
Domains yourdomain.com
Return URLs https://yourdomain.com/auth/apple/callback
  1. 点击 Next > Done > Continue > Save

步骤 3:创建 Sign in with Apple 密钥

  1. 在侧边栏进入 Keys
  2. 点击 + 创建新密钥
  3. 输入密钥名称(如 "MyApp Sign in with Apple")
  4. 启用 Sign in with Apple
  5. 点击 Configure
  6. 选择 Primary App ID
  7. 点击 Save > Continue > Register
  8. 立即下载密钥文件(.p8)

重要: 密钥只能下载一次,请妥善保存。

  1. 记录:
  • Key ID - 在密钥详情页显示
  • Team ID - 在 Membership 中查找

步骤 4:生成 Client Secret

Apple 使用 JWT 作为 client secret,需自行生成:

所需信息

查找位置
Team ID Membership > Team ID
Key ID Keys > 您的密钥
Services ID Identifiers > Services IDs
Private Key 下载的 .p8 文件

生成 JWT

使用 Node.js 生成 client secret:

const jwt = require('jsonwebtoken');
const fs = require('fs');

const privateKey = fs.readFileSync('AuthKey_XXXXXXXXXX.p8');

const clientSecret = jwt.sign({}, privateKey, {
  algorithm: 'ES256',
  expiresIn: '180d',
  audience: 'https://appleid.apple.com',
  issuer: 'YOUR_TEAM_ID',
  subject: 'com.yourcompany.myapp.web', // Services ID
  keyid: 'YOUR_KEY_ID'
});

console.log(clientSecret);

注意: Client secret 会过期,请在过期前(最长 6 个月)重新生成。

步骤 5:在 OpenDev 中配置

  1. 登录 OpenDev 平台
  2. 进入 OAuth 渠道
  3. 添加或编辑 Apple OAuth 渠道
  4. 填写配置:
{
  "provider": "apple",
  "clientId": "com.yourcompany.myapp.signin",
  "teamId": "YOUR_TEAM_ID",
  "keyId": "YOUR_KEY_ID",
  "privateKey": "[encrypted_private_key]",
  "callbackUrl": "https://yourdomain.com/auth/callback?provider=apple",
  "scopes": ["email", "name"]
}

说明:

  • privateKey 需用项目加密工具加密后再存入数据库
  • 统一回调格式为 /auth/callback?provider=apple(POST)
  • Web 弹窗模式可省略 teamId、keyId、privateKey、callbackUrl
  • 也支持使用 appSecret 作为 privateKey 的别名

配置字段

字段 Web 弹窗 服务端认证 说明
Client ID 必填 必填 Services ID
Team ID 可选 必填 Apple 开发者 Team ID
Key ID 可选 必填 Sign in with Apple 密钥 ID
Private Key 可选 必填 .p8 文件的加密内容
Callback URL 可选 必填 授权码模式的重定向 URL
Scopes 可选 可选 请求的数据(email, name)

加密 Private Key

存入前使用以下命令加密:

cd backend
node scripts/tools/encrypt-apple-key.js ../configure/AuthKey_XXXXXXXXXX.p8

将加密输出填入数据库配置的 privateKey 字段。

步骤 6:iOS 实现

在 Xcode 中添加能力:

  1. 在 Xcode 中打开项目
  2. 选择 target
  3. 进入 Signing & Capabilities
  4. 点击 + Capability
  5. 添加 Sign in with Apple

步骤 7:测试集成

iOS 测试

  1. 使用真机(模拟器无法测试 Sign in with Apple)
  2. 使用 Apple ID 登录
  3. 验证认证流程

Web 测试

  1. 访问您的 Web 应用
  2. 点击「通过 Apple 登录」
  3. 完成 Apple 认证
  4. 验证回调收到用户数据

OAuth 响应示例

{
  "provider": "apple",
  "providerId": "001234.abc123def456.0123",
  "email": "user@privaterelay.appleid.com",
  "name": "John D.",
  "emailVerified": true
}

注意: Apple 仅在首次授权时返回姓名和邮箱,请立即保存。

故障排查

错误:invalid_client

解决: 核对 Services ID 与 Client ID;检查 private key 格式;确认 client secret JWT 未过期。

错误:invalid_grant

解决: 授权码可能已过期(5 分钟)或已被使用;确认 redirect URI 完全一致。

未收到用户信息

解决: 姓名和邮箱仅在首次授权时发送,检查用户是否曾授权过该应用。

安全最佳实践

  1. 保护 Private Key - 勿在客户端代码中暴露
  2. 验证 ID Token - 验证 Apple 的 JWT 签名
  3. 校验 Nonce - 防止重放攻击
  4. 处理撤销 - 监听凭证撤销通知
  5. 轮换密钥 - 在过期前生成新的 client secret

相关文档