# @arendajaelu/nestjs-passport-apple 中文文档

规范地址：https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/

版本：2\.1\.0
npm 元数据更新时间：2026-07-22T11:46:24.651Z
中文译文更新时间：2026-11-06T18:20:01.650Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40arendajaelu/nestjs-passport-apple
原文对照：https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/?lang=original
项目主页：https://github.com/arendajaelu/nestjs-passport-apple#readme
源码仓库：https://github.com/arendajaelu/nestjs-passport-apple

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：48 kB，11 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=18\.0\.0
- 运行依赖：4 个
- 首次发布：2022-08-11T19:34:25.474Z
- 最新版本发布：2026-07-22T11:46:24.472Z
- 近 30 天下载量：37345（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：12（近 12 个月 1 个）

## 中文简介

Nestjs 护照的苹果策略

## 安装

```sh
npm install @arendajaelu/nestjs-passport-apple
```

也可以使用：`pnpm add @arendajaelu/nestjs-passport-apple`、`yarn add @arendajaelu/nestjs-passport-apple`、`bun add @arendajaelu/nestjs-passport-apple`

## README

# NestJS Passport Apple 策略 — 与 Apple 为 NestJS 签名

[![npm version](https://img.shields.io/npm/v/@arendajaelu/nestjs-passport-apple.svg)](https://www.npmjs.com/package/@arendajaelu/nestjs-passport-apple) [![npm downloads](https://img.shields.io/npm/dt/@arendajaelu/nestjs-passport-apple.svg)](https://www.npmjs.com/package/@arendajaelu/nestjs-passport-apple) [![license](https://img.shields.io/npm/l/@arendajaelu/nestjs-passport-apple.svg)](https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/LICENSE) [![node](https://img.shields.io/node/v/@arendajaelu/nestjs-passport-apple.svg)](https://nodejs.org/) [![CI](https://github.com/arendajaelu/nestjs-passport-apple/actions/workflows/ci.yml/badge.svg)](https://github.com/arendajaelu/nestjs-passport-apple/actions/workflows/ci.yml)

**苹果在几分钟内登录了雀巢JS.** 纳入护照战略 **用苹果签名** 输入 NestJS 应用程序 – Apple OAuth 2.0 认证,身份符 (JWT) 验证,刷新令牌验证,撤销令牌以删除账户,以及 Apple 的服务器对服务器通知,都用一个输入,测试的软件包 **900k+ 下载**。 。 。 .

与 `@nestjs/passport` 财务报告和审定财务报表 `AuthGuard`,支持网络应用(Services ID)和原生iOS/macOS应用(App ID),并在您代码看到之前,验证所有与苹果公钥相对抗的令牌.

## 特征

-   🍎 **插件和游戏苹果登录** - 与NestJS 10 & 11通过 `AuthGuard`
-   🔐 **在你看到它之前已经验证过** – ID 代号与 Apple 的公共密钥对照检查; 您 `validate` 只接收可信任的数据
-   🧾 **类型 `Profile`** 电子邮件、 校验状态和隐藏我的电子邮件旗
-   📱 **本地应用程序支持** 核查iOS/macOS应用程序中的身份标志,并提供非ce保护(`verifyIdToken`(中文(简体) )
-   ♻️ **会话验证** ——检查用户的Apple授权是否仍然有效(`refreshAccessToken`(中文(简体) )
-   🗑️ **账户删除准备** —— App Store 准则 5.1.1 (五) 撤销令状 (`revokeToken`(中文(简体) )
-   📨 **服务器对服务器的通知** ——验证苹果公司签署的账户事件(`verifyServerNotification`(中文(简体) )
-   🛡️ **CSRF 保护** ——可选 OAuth `state` 生成和验证
-   ✅ **完全测试** ——单位和集成套件运行于模拟 Apple 服务器的全流,所发布的类型由 CI 中真正的严格模式 NestJS 消费者编译

## 所需资源

-   与 NestJS 10 一起使用的节点.js 18 或以后
-   与 NestJS 11(NestJS 11本身需要 Node.js 20)一起使用时的节点.js 20或更后

## 安装

```bash
npm install @arendajaelu/nestjs-passport-apple
```

## 使用量

### 战略设置

以下示例显示所有常用选项:

```typescript
import { Injectable } from '@nestjs/common';
import { AuthGuard, PassportStrategy } from '@nestjs/passport';
import { Strategy, Profile } from '@arendajaelu/nestjs-passport-apple';

const APPLE_STRATEGY_NAME = 'apple';

@Injectable()
export class AppleStrategy extends PassportStrategy(Strategy, APPLE_STRATEGY_NAME) {
  constructor() {
    super({
      clientID: process.env.APPLE_OAUTH_CLIENT_ID,
      teamID: process.env.APPLE_TEAMID,
      keyID: process.env.APPLE_KEYID,
      key: process.env.APPLE_KEY_CONTENTS,
      // OR
      keyFilePath: process.env.APPLE_KEYFILE_PATH,
      callbackURL: process.env.APPLE_OAUTH_CALLBACK_URL,
      scope: ['email', 'name'],
      // state: true, // recommended in production for CSRF protection; requires express-session
      passReqToCallback: false,
    });
  }

  async validate(_accessToken: string, _refreshToken: string, profile: Profile) {
    return {
      emailAddress: profile.email,
      firstName: profile.name?.firstName || '',
      lastName: profile.name?.lastName || '',
    };
  }
}

@Injectable()
export class AppleOAuthGuard extends AuthGuard(APPLE_STRATEGY_NAME) {}
```

> **说明**: 登记册 `AppleStrategy` 输入 `providers` 模块的数组.

### 控制器终点

```typescript
import { Controller, Get, Post, Req, UseGuards } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AppleOAuthGuard } from './strategies/apple.strategy';

@ApiTags('oauth')
@Controller('oauth')
export class OAuthController {
  @Get('apple')
  @UseGuards(AppleOAuthGuard)
  async appleLogin() {}

  @Post('apple/callback')
  @UseGuards(AppleOAuthGuard)
  async appleCallback(@Req() req) {
    return req.user;
  }
}
```

> Apple 将授权召回作为 `application/x-www-form-urlencoded` HTTP POST 当范围如: `name` 或者说 `email` 请求(战略总是发出 `response_mode=form_post`) (中文(简体) ). 因此,回调路线必须是 `@Post` 已启用 URL 编码的正文解析器 —— NestJS 默认允许此功能 。 回调 URL 必须完全匹配在苹果开发者门户网站上注册的 HTTPS 返回 URL; 苹果不接受 `localhost` 或 IP 地址回调 URL 。 授权代码为单用,5分钟后失效.

### 战略选项

| 选项 | 需求 | 说明 |
| --- | --- | --- |
| `clientID` | 对 | 用作 OAuth 客户端标识的 Apple 服务ID( 或 App ID) |
| `teamID` | 对 | 苹果开发者团队 ID |
| `keyID` | 对 | 用 Apple 私钥标识符号 |
| `key` | 对\* | 私钥的内容 。 提供其中之一 `key` 或者说 `keyFilePath` |
| `keyFilePath` | 对\* | 私密密钥文件的路径; 装入 `fs.readFileSync` |
| `callbackURL` | 没有 | OAuth 重定向 URI; 必须匹配在 Apple 注册的返回 URL |
| `scope` | 没有 | 瞄准镜阵等. `['email', 'name']` |
| `state` | 没有 | 启用 OAuth `state` 生成和验证以防范CSRF:在重定向到苹果公司之前将随机值存储在会话中,并与苹果公司帖子回放的值进行比较. 大力推荐出产. 要求数 `express-session` 或兼容会话中间软件。 默认为 `false` |
| `store` | 没有 | 自定义状态存储执行 `store(req, callback)` 财务报告和审定财务报表 `verify(req, state, callback)`,用于没有会话中间软件的部署 |
| `sessionKey` | 没有 | 存储状态的会话密钥; 默认为 `apple:<hostname>` |
| `passReqToCallback` | 没有 | 通过请求,作为第一个论据: `validate`; 默认为 `false` |
| `clientSecretExpiry` | 没有 | 生成客户端秘密JWT的寿命;默认为 `'5 minutes'`。密钥在到期前自动被缓存和重生成 |
| `authorizationURL` | 没有 | 默认为 `https://appleid.apple.com/auth/authorize` |
| `tokenURL` | 没有 | 默认为 `https://appleid.apple.com/auth/token` |
| `revokeURL` | 没有 | 默认为 `https://appleid.apple.com/auth/revoke` |
| `jwksURL` | 没有 | JWKS 端点用于获取 Apple 的公钥; 默认为 `https://appleid.apple.com/auth/keys` |

### 验证召回

认证成功后, `validate` 接收 `accessToken`, (中文(简体) ), `refreshToken`,并核实 `profile`。返回的值变为 `req.user`存储 `refreshToken` 如果您打算验证会话或稍后取消访问.

### 配置对象

```typescript
{
  id: string;               // stable Apple user identifier (the `sub` claim)
  provider: 'apple';
  email?: string;
  emailVerified?: boolean;
  isPrivateEmail?: boolean; // true when the address is a Hide My Email relay
  name?: {                  // present only on the user's first authorization
    firstName: string;
    lastName: string;
  };
}
```

> **重要**: 总是将应用程序账户与 `profile.id`,而不是电子邮件地址。 苹果贴出 `user` 对象( 包含) `name`)仅在用户使用期间 **第一个** ——在当时坚持. 因为名称来源于浏览器的形成后而非所签名的身份符号,所以在存储或显示之前验证并消毒. 其后授权不包括 `user` 对象; 身份符号通常带有电子邮件请求, 但是应用程序也应该容忍缺失的电子邮件( 有些管理好的苹果账户没有).

### 私人转发电子邮件地址

不通过检查电子邮件域来识别或过滤苹果中继地址; 依赖已核实的地址 `isPrivateEmail` 换成旗帜。 如果您的电子邮件验证或发送基础设施按域过滤, 它必须接受 Apple 的所有中继域 : `private.icloud.com` (用于2026年年中产生的地址)以及遗产 `privaterelay.appleid.com` 财务报告和审定财务报表 `icloud.com`。 。 。 .

## 超出登录范围

战略实例将剩余Sign与苹果的生命周期操作相接而来. 由于这一策略是雀巢JS的提供商,可以在需要这些操作的地方注入.

### 正在验证本地 App 的身份

当您的后端也使用 iOS/macOS 应用程序服务时 `ASAuthorizationAppleIDCredential`,该应用程序直接提交身份标志。 根据苹果的公用钥匙校验:

```typescript
const claims = await appleStrategy.verifyIdToken(identityToken, {
  audience: 'com.example.bundleid', // the app's bundle ID, from server-side configuration
  nonce: expectedNonce,             // the nonce your server issued for this sign-in attempt
});
// claims.sub is the stable Apple user identifier
```

-   `audience` 默认为配置 `clientID`; 当为不同的客户端发布符号时, 如应用的捆绑ID , 将它覆盖 .
-   当a `nonce` 提供, 核查失败, 除非信使的非ce 索赔完全匹配。 苹果在使用非ce时需要非ce验证,作为防止回放攻击的保护.

> **警卫**: 预期 `audience` 财务报告和审定财务报表 `nonce` 必须是来自信任的服务器侧配置或服务器侧会话状态。 绝不接受来自未认证请求的任一值.

### 验证刷新键并获取新键

```typescript
const tokens = await appleStrategy.refreshAccessToken(refreshToken);
// tokens: { access_token, token_type, expires_in, id_token }
```

苹果公司建议验证一个存储的刷新令牌,每天不超过一次;更频繁的验证有节奏的风险. 一个 `invalid_grant` 错误指授权代码或刷新令牌无效,过期,已消耗,被撤销,或与所配置的客户端不符——在任何情况下,应用程序都应要求用户再次认证.

### 撤销托肯( 账户删除)

App Store Review 准则 5.1.1(v) 要求提供账户创建的应用程序也提供账户删除,包括撤销带有 Apple 令牌的签名:

```typescript
await appleStrategy.revokeToken(refreshToken); // token_type_hint defaults to 'refresh_token'
// or
await appleStrategy.revokeToken(accessToken, 'access_token');
```

一个成功的呼叫在苹果的授权下撤销了该令牌及其相關的Sign,或确认该令牌已经无效——苹果在两种情况下都返回了HTTP 200.

> **说明**:撤销苹果令牌不会删除应用程序账户或终止应用程序自己的会话. 被撤销后,该应用程序仍然负责删除适用的用户数据,去掉所储存的令牌,清除本地会话和饼干,并将客户端还原为未经认证的状态.

### 处理服务器对服务器的通知

当用户更改与您应用程序的关系时,苹果可以通知您的服务器. 在 Apple 开发者门户网站中注册一个通知端点 URL; 然后, Apple 将签名的事件作为 HTTP POST 发送, 并带有表单的 JSON 机构 `{ "payload": "<signed JWS>" }`在对事件采取行动之前验证签名 :

```typescript
@Post('apple/notifications')
async appleNotifications(@Body() body: { payload: string }) {
  const notification = await this.appleStrategy.verifyServerNotification(body.payload);

  switch (notification.events.type) {
    case 'email-enabled':   // user enabled email forwarding
    case 'email-disabled':  // user disabled email forwarding
      break;
    case 'consent-revoked': // user revoked authorization — end their sessions
      break;
    case 'account-deleted': // user deleted their Apple Account — remove associated data
      break;
  }
}
```

`verifyServerNotification` 验证 JWS 签名对 Apple 的公钥, 以及发行人和受众, 并将权利主张与 `events` 已分析有效载荷。 图书馆只进行核查;决定如何就每个事件采取行动仍然是应用程序的责任。 核查失败——将这类请求视为伪造和拒绝.

> **重放保护**: 经核实的通知载有: `jti` (独特的通知ID). 因为抓获的快递可以重新播放到您的端点,同时仍留在其有效性窗口内,所以继续处理 `jti` 值(数据库、Redis等),并在对事件采取行动前拒绝重复:
> 
> ```typescript
> const accepted = await this.notificationStore.claim(notification.jti);
> if (!accepted) {
>   throw new ConflictException('Notification already processed');
> }
> ```

### 类型脚本: 请求打字

战略的申报类型完全自成一体——不 `@types/express` 或者说 `@types/passport-strategy` 所需经费。 请求类型是通用的,所以 `passReqToCallback` 和自定义状态存储工作

```typescript
import type { Request } from 'express'; // or FastifyRequest from 'fastify'

export class AppleStrategy extends PassportStrategy(Strategy<Request>, 'apple') {
  constructor() {
    super({ /* options */, passReqToCallback: true });
  }

  validate(req: Request, accessToken: string, refreshToken: string, profile: Profile) {
    return { id: profile.id };
  }
}
```

## 测试

在Node.js本土测试跑道上建造的拥有全面自动化测试套件的寄存器船——不需要额外的测试依赖性:

```bash
npm test
```

套房包括两个层面:

-   **单位测试** (单位:千美元)`test/strategy.test.js`: 构造器验证,授权重定向参数, Apple 错误处理,剖析配置要求(包括字符串和布尔格式) `email_verified` 财务报告和审定财务报表 `is_private_email`),撤销并刷新请求格式,客户端秘密生成,过期驱动再生,每个客户端秘密缓存,以及状态商店行为(基于会场的验证,错配拒绝,以及自定义商店).
-   **融合测试** (单位:千美元)`test/integration.test.js`:针对苹果的指代和JWKS端点的本地模拟被执行的完整认证流有真实的RS256签名的身份指代,以及负面案例——错误的受众,未知的签名密钥,过期的指代,非ce不匹配,以及伪造的服务器通知.

## 教学

包括认证、吊销和Apple使用寿命周期的完整标志:

[**Apple 登录 NestJS 于 2026–2027 : 认证、托肯撤销和更多完整指南**](https://medium.com/@joosepwong/apple-login-with-nestjs-in-2026-2027-a-complete-guide-to-authentication-token-revocation-and-9ec3f08863e5)

苹果开发者门户网站设置的原始行走通道也可用:

[**如何使用 NestJS 在秒中执行 Apple 登录**](https://blog.devgenius.io/how-to-implement-apple-login-with-nestjs-in-seconds-b88f05abe847)

## 财务问题

### 我如何在 NestJS 执行 Apple 登录?

安装此软件包, 注册显示于 [战略设置](https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/#readme-strategy-setup) 作为雀巢JS的供应商, 守护你的路线 `AuthGuard('apple')`编辑 [完整指南](https://medium.com/@joosepwong/apple-login-with-nestjs-in-2026-2027-a-complete-guide-to-authentication-token-revocation-and-9ec3f08863e5) 走遍了每个步骤,包括苹果开发者门户配置.

### 我如何从我的NestJS后端的iOS应用程序中验证出苹果的身份代号??

使用 [`verifyIdToken`](https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/#readme-verifying-a-native-apps-identity-token) 你的应用软件的捆绑 ID作为观众。 它验证了针对Apple的JWKS的RS256签名,加上发行者,到期,和(可选择的)非ce.

### 我如何撤销与苹果公司签入的签名 以删除账户?

打电话 [`revokeToken`](https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/#readme-revoking-tokens-account-deletion) 与用户存储的刷新符号。 这满足了App Store Review 准则 5.1.1 (v),该准则要求提供账户创建的应用程序在账户删除时也撤销了苹果的令牌.

### 首次Apple登录后为何用户名缺失??

苹果发送 `name` (和 `user` 对象)仅在用户的 **第一个** 授权。 坚持在第一个登录上——看 [配置对象](https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/#readme-profile-object)。 。 。 .

### 这是否与新的 `private.icloud.com` 隐藏我的电子邮件地址吗 ?

对 战略暴露了一个经过验证的 `isPrivateEmail` 旗子,所以你不需要自己匹配接力域——看 [私人转发电子邮件地址](https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/#readme-private-relay-email-addresses)。 。 。 .

### 当用户取消访问或删除其苹果账户时, 能否通知我的服务器 ?

是 – 向苹果公司注册一个通知端点,并通过 [`verifyServerNotification`](https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/#readme-processing-server-to-server-notifications)。 。 。 .

## 许可证

许可证根据 [麻省理工学院](https://npmcn.com/package/%40arendajaelu/nestjs-passport-apple/LICENSE)。 。 。 .

* * *

_关键词:与Apple,Apple登录NestJS,NestJS Apple OAuth,护照-apple,Apple OAuth2策略,苹果标志,苹果ID认证,验证苹果身份令牌,苹果令牌撤销,苹果服务器对服务器通知,隐藏我的电子邮件,NestJS认证,Passport.js Apple策略_

## 常见问题

### @arendajaelu/nestjs-passport-apple 是什么？

Nestjs 护照的苹果策略

### 如何安装 @arendajaelu/nestjs-passport-apple？

在项目目录运行 npm install @arendajaelu/nestjs-passport-apple，或使用 pnpm add / yarn add / bun add。

### @arendajaelu/nestjs-passport-apple 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @arendajaelu/nestjs-passport-apple 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @arendajaelu/nestjs-passport-apple 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @arendajaelu/nestjs-passport-apple 可以商用吗？

@arendajaelu/nestjs-passport-apple 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @arendajaelu/nestjs-passport-apple 的下载量有多少？

根据 npm 官方下载统计，@arendajaelu/nestjs-passport-apple 在 2026/10/07 – 2026/11/05 这 30 天内被下载 37,345 次，日均约 1,245 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @arendajaelu/nestjs-passport-apple 还在维护吗？

最新版本 2\.1\.0 发布于 2026/07/22（3 个月前）；至今共发布 12 个版本，其中过去 12 个月发布了 1 个；首次发布于 2022/08/12。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

