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。
- 登录 Authany 管理台
- 选择您的项目,然后进入 Applications,打开您的客户端用于登录的应用(或新建一个,例如一个 Single Page Application)
- 在 Access Token 部分,打开 Issue JWT as access token
- 记下您的 Endpoint(例如
https://your-project.authanyid.com)和 Client ID,稍后会用到 - 点击 Save
注意
如果未启用 Issue JWT as access token,Authany 会签发不透明访问令牌(opaque access token),此 SDK 无法离线验证该令牌,请求会被以 401 拒绝。
构建您的 NestJS 应用¶
步骤 1:创建 NestJS 项目¶
步骤 2:安装 Authany SDK¶
这也会安装 @nestjs/config,我们会用它从环境变量中读取配置:
步骤 3:配置环境变量¶
在项目根目录创建一个 .env 文件:
说明
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) 应用该守卫。
运行应用¶
该 API 会监听 http://localhost:3000。
测试集成¶
无需令牌即可访问公开路由:
没有有效令牌时,受保护的路由会被拒绝:
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}
模块选项¶
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,在守卫之外验证令牌。
后续步骤¶
- JWT 访问令牌参考:完整的声明列表
- 在后端验证 JWT:与框架无关的方式
@authgear/nestjs文档与 API 参考