我正在使用 NestJS 10。我想创建一个保护端点的防护,不仅在用户登录时,而且在他们确认其电子邮件时也保护端点。我正在使用 NestJS/passport,并像这样创建 JWT 令牌
async getTokens(userId: string, username: string) {
const [accessToken, refreshToken] = await Promise.all([
this.jwtService.signAsync(
{
sub: userId,
username,
},
{
secret: this.configService.get<string>('JWT_ACCESS_SECRET'),
expiresIn: ACCESS_TOKEN_DURATION,
},
),
this.jwtService.signAsync(
{
sub: userId,
username,
},
{
secret: this.configService.get<string>('JWT_REFRESH_SECRET'),
expiresIn: REFRESH_TOKEN_DURATION,
},
),
]);
return {
accessToken,
refreshToken,
};
}
我在我的身份验证模块中配置了此 AccessTokenStrategy ...
type JwtPayload = {
sub: string;
username: string;
};
@Injectable()
export class AccessTokenStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
console.log("access token strategy ...");
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_ACCESS_SECRET,
});
}
validate(payload: JwtPayload) {
return payload;
}
}
但我不知道如何保护我的电子邮件确认保护。我的用户实体有一个布尔值“isEmailConfirmed”属性,但如果我要构建这样的防护,我不太确定如何从有效负载中添加/提取该属性。
您没有提供数据库引擎,所以我假设它是 Prisma,尽管它在这里并不那么重要。
您可以按如下方式创建守卫:
import { Injectable, type CanActivate, type ExecutionContext } from '@nestjs/common';
import { DbUserService } from '@/modules/database/user.service';
interface GuardRequest {
readonly userId: string;
}
@Injectable()
export class IsEmailConfirmedGuard implements CanActivate {
constructor(private readonly dbUserService: DbUserService) {}
public async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<GuardRequest>();
const user = request.userId;
const isEmailConfirmed = await this.dbUserService.isEmailConfirmed(
userId,
);
return isEmailConfirmed;
}
}
当然,
isEmailConfirmed
函数应该根据isEmailConfirmed
,在数据库中查询用户的userId
属性值。
然后将防护应用到端点控制器:
import { Body, Controller, HttpCode, HttpStatus, Param, Patch, UseGuards } from '@nestjs/common';
import { IsEmailConfirmedGuard } from '@/guards/is-email-confirmed.guard';
import Routes from './example.routes';
@Controller(Routes.EXAMPLE_CONTROLLER)
export class ExampleController {
@UseGuards(IsEmailConfirmedGuard)
@Patch(Routes.EXAMPLE)
@HttpCode(HttpStatus.OK)
public async example(
): Promise<void> {
return;
}
}