跳转至

NestJS

使用 @authgear/nestjs SDK,通过 Authany 保护 NestJS API。该 SDK 会离线验证 Authany 的 JWT 访问令牌(通过 OIDC 发现和 JWKS),并为您提供一个 NestJS 模块、一个身份验证守卫(Guard)和若干装饰器,因此只需几行代码即可保护一个路由。

完整的示例应用可以在 authgear/authgear-example-nestjs 找到。

说明

此 SDK 用于资源服务器一侧:用来验证您的 API 收到的访问令牌,不执行登录流程。您的用户通过独立的客户端登录(例如 单页应用、移动应用,或任何 OAuth 客户端),该客户端随后会携带访问令牌调用您的 NestJS API。

您将构建的内容:

  • 一个无需令牌的公开路由(GET /health)
  • 一个受保护的路由(GET /me),返回已认证用户的声明

在 Authany 中设置您的应用

步骤 1:启用 JWT 访问令牌

该 SDK 会离线验证 JWT 访问令牌,因此签发您 API 所接受令牌的应用必须签发 JWT。

  1. 登录 Authany 管理台
  2. 选择您的项目,然后进入 Applications,打开您的客户端用于登录的应用(或新建一个,例如一个 Single Page Application)
  3. 在 Access Token 部分,打开 Issue JWT as access token
  4. 记下您的 Endpoint(例如 https://your-project.authanyid.com)和 Client ID,稍后会用到
  5. 点击 Save

注意

如果未启用 Issue JWT as access token,Authany 会签发不透明访问令牌(opaque access token),此 SDK 无法离线验证该令牌,请求会被以 401 拒绝。


构建您的 NestJS 应用

步骤 1:创建 NestJS 项目

npm i -g @nestjs/cli
nest new my-api
cd my-api

步骤 2:安装 Authany SDK

npm install @authgear/nestjs

这也会安装 @nestjs/config,我们会用它从环境变量中读取配置:

npm install @nestjs/config

步骤 3:配置环境变量

在项目根目录创建一个 .env 文件:

AUTHGEAR_ENDPOINT=https://your-project.authanyid.com
AUTHGEAR_CLIENT_ID=your-client-id

说明

AUTHGEAR_CLIENT_ID 是可选的。设置后,SDK 会额外校验令牌的 client_id 声明是否与其匹配。

步骤 4:注册 Authany 模块

在您的根模块中注册 AuthgearModule。将 global: true 设置后,会把该守卫注册为全局守卫,因此默认情况下所有路由都会受到保护,除非显式标记为公开。

// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AuthgearModule } from '@authgear/nestjs';
import { AppController } from './app.controller';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    AuthgearModule.forRootAsync({
      global: true,
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        endpoint: config.getOrThrow<string>('AUTHGEAR_ENDPOINT'),
        clientID: config.get<string>('AUTHGEAR_CLIENT_ID'),
      }),
    }),
  ],
  controllers: [AppController],
})
export class AppModule {}

说明

如果您的配置是静态的,可以使用 AuthgearModule.forRoot({ endpoint: '...', global: true }),而不必使用 forRootAsync。

步骤 5:保护您的路由

在全局注册守卫后,使用 @Public() 标记公开路由。使用 @CurrentUser() 参数装饰器读取已认证的用户。

// src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { Public, CurrentUser, AuthgearClaims } from '@authgear/nestjs';

@Controller()
export class AppController {
  // Public — no token required
  @Public()
  @Get('health')
  health() {
    return { status: 'ok' };
  }

  // Protected — requires a valid Authgear access token
  @Get('me')
  me(@CurrentUser() user: AuthgearClaims) {
    return {
      sub: user.sub,
      isVerified: user.isVerified,
      isAnonymous: user.isAnonymous,
    };
  }
}

AuthgearClaims 会暴露常见声明(sub、iss、aud、clientID、isVerified、isAnonymous、canReauthenticate),并通过 raw 提供完整解码后的 payload,以便获取任何自定义声明。

说明

希望按需保护单个路由,而不是全局保护?可以省略 global: true,改为在每个控制器或处理函数上使用 @UseGuards(AuthgearAuthGuard) 应用该守卫。


运行应用

npm run start:dev

该 API 会监听 http://localhost:3000。


测试集成

无需令牌即可访问公开路由:

curl -i http://localhost:3000/health
# 200 {"status":"ok"}

没有有效令牌时,受保护的路由会被拒绝:

curl -i http://localhost:3000/me
# 401 {"message":"Missing bearer token","error":"Unauthorized","statusCode":401}

要调用受保护的路由,请将 Authany 访问令牌作为 Bearer 令牌发送:

curl -i http://localhost:3000/me \
  -H "Authorization: Bearer <ACCESS_TOKEN>"
# 200 {"sub":"...","isVerified":true,"isAnonymous":false}

说明

通过客户端应用让用户登录即可获取访问令牌。示例项目包含一个小型前端,可以帮您完成登录并调用受保护的 API。如果要构建自己的客户端,请参阅单页应用或原生/移动应用指南。


模块选项

forRoot() 以及 forRootAsync() 工厂函数返回的对象接受以下参数:

Option Type Required Default Description
endpoint string ✓ — Authany 项目端点,用于 OIDC 发现和 JWKS。
clientID string — 设置后,验证器还会校验令牌的 client_id 声明。
global boolean false 将该守卫注册为全局 APP_GUARD,使所有路由都受到保护。
jwksCacheMaxAge number — JWKS 缓存的最长有效期,单位为毫秒。
clockToleranceSeconds number 0 exp/iat 校验的宽容时间,单位为秒。

您也可以注入 AuthgearTokenService,在守卫之外验证令牌。


后续步骤