跳转到内容

添加 Blacklist

在 access token 过期之前将其撤销。

本指南承接添加会话管理,添加 blacklist 功能。

撤销会话会使 refresh token 失效,但已经签发的 access token 在过期之前仍然有效。blacklist 功能通过拒绝会话已被撤销的 access token 来补上这个空缺。

当一个会话被撤销时,它的会话 id 会被加入黑名单,TTL 使用配置的 access token 有效期。之后每个受 access token 保护的请求都会执行一次轻量的 Redis 查询。

完成本指南后,登出或撤销一个会话,也会阻止相关的 access token 访问受保护路由。

添加功能

运行 CLI 命令:

Terminal window
brkpt auth add blacklist

CLI 会添加一个新的 features/blacklist/ 文件夹。

实现 BlacklistAdapter

blacklist 适配器只需要存储被撤销的会话 id,并检查某个会话 id 是否在黑名单中。

创建 blacklist.adapter.ts,实现基于 Redis 的 blacklist 适配器:

  • 文件夹src/
    • 文件夹brkpt-auth/
      • 文件夹adapters/
        • blacklist.adapter.ts
src/brkpt-auth/adapters/blacklist.adapter.ts
import { Inject, Injectable } from '@nestjs/common';
import { type RedisClientType } from 'redis';
import { BlacklistPort } from '../features/blacklist/blacklist.port';
@Injectable()
export class BlacklistAdapter implements BlacklistPort {
constructor(
@Inject('REDIS_CLIENT') private readonly redis: RedisClientType,
) {}
private key(sessionId: string) {
return `blacklist:${sessionId}`;
}
async add(sessionId: string, ttlMs: number): Promise<void> {
await this.redis.set(this.key(sessionId), '1', {
expiration: { type: 'PX', value: ttlMs },
});
}
async exists(sessionId: string): Promise<boolean> {
return !!(await this.redis.exists(this.key(sessionId)));
}
}

注册功能

更新 features.ts,把 BlacklistAdapter 传给 blacklistFeature:

src/brkpt-auth/features.ts
import { BlacklistAdapter } from './adapters/blacklist.adapter';
import { CoreAdapter } from './adapters/core.adapter';
import { CredentialsAdapter } from './adapters/credentials.adapter';
import { SessionAdapter } from './adapters/session.adapter';
import { FeatureConfig } from './common/interfaces';
import { blacklistFeature } from './features/blacklist/blacklist.feature';
import { coreFeature } from './features/core/core.feature';
import { credentialsFeature } from './features/credentials/credentials.feature';
import { sessionFeature } from './features/session/session.feature';
export const features: FeatureConfig[] = [
coreFeature(CoreAdapter),
blacklistFeature(BlacklistAdapter),
credentialsFeature(CredentialsAdapter),
sessionFeature(SessionAdapter),
];

BlacklistAdapter 也依赖 REDIS_CLIENT。如果你已经完成了添加会话管理,RedisModule 应该已经被 BrkptAuthModule 导入过了,这里不需要再额外导入。

启动应用:

Terminal window
pnpm start:dev

使用开始使用中创建的账号,或者用 /auth/sign-up 创建一个新账号。登录并保留返回的 access token。

登出

用这个 access token 调用 /auth/sign-out:

POST /auth/sign-out
Authorization: Bearer <access-token>

复用该 access token

用同一个 access token 调用 /auth/me:

GET /auth/me
Authorization: Bearer <access-token>

这个请求应该被拒绝,因为这个 access token 属于一个已被列入黑名单的会话 id。