auth.guard.ts
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { InjectModel } from '@nestjs/mongoose';
import { Request } from 'express';
import { Model } from 'mongoose';
import { User } from '../user/entities/user.entity';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
@InjectModel(User.name)
private userModel: Model<User>,
private jwtService: JwtService,
private readonly configService: ConfigService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) {
throw new UnauthorizedException(
'You are not authorized to access this resource.',
);
}
try {
const payload = await this.jwtService.verifyAsync(token, {
secret: this.configService.get<string>('JWT_SECRET'),
});
const user = await this.userModel.findById(payload.id);
if (!user) {
throw new UnauthorizedException('User not found.');
}
request['user'] = user;
console.log('request.user -->', request.user);
} catch {
throw new UnauthorizedException(
'You are not authorized to access this resource.',
);
}
return true;
}
private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}
角色.guard.ts
import {
Injectable,
CanActivate,
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Role } from '../enums/role.enum';
import { ROLES_KEY } from '../decorators/roles.decorator';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
const isAuthorozed = requiredRoles.some(
(role) => user.role?.includes(role),
);
if (!isAuthorozed) {
throw new UnauthorizedException({
message: 'You are not authorized person to access this resource.',
statusCode: 401,
});
}
}
}
角色.decorator.ts
import { SetMetadata } from '@nestjs/common';
import { Role } from '../enums/role.enum';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
book.controller.ts
@UseGuards(AuthGuard)
@Roles(Role.USER)
@Get()
async getAllBooks(
@Req() req: Request,
@Res() res: Response,
@Query() query: any,
): Promise<any> {
const books = await this.bookService.findAll(query);
return res.status(HttpStatus.OK).json({
data: books,
statusCode: 200,
message: 'Books fetched successfully.',
});
}
app.module.ts
@Module({
imports: [
MongooseModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
uri: configService.get<string>('MONGO_URI'),
dbName: configService.get<string>('DATABASE_NAME'),
}),
inject: [ConfigService],
}),
ConfigModule.forRoot({
envFilePath: '.env',
isGlobal: true,
}),
BookModule,
AuthModule,
UserModule,
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_GUARD,
useClass: RolesGuard,
},
],
})
在我的场景中,我使用了两个自定义防护,即身份验证和基于角色的授权。如果我在书籍控制器中使用它们(我在上面的代码中提到过),它会忽略
AuthGuard
并直接执行RoleGuard
。
但我想先执行
AuthGuard
,因为我需要用户详细信息来检查RoleGuard
中的用户角色。
提前致谢。
快乐编码!
由于
RolesGuard
是一个全局守卫,它会在 AuthGuard
之前预先执行,在我看来,AuthGuard
应该在 AppModule
级别而不是控制器级别定义:
@Module({
imports: [
MongooseModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
uri: configService.get<string>('MONGO_URI'),
dbName: configService.get<string>('DATABASE_NAME'),
}),
inject: [ConfigService],
}),
ConfigModule.forRoot({
envFilePath: '.env',
isGlobal: true,
}),
BookModule,
AuthModule,
UserModule,
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_GUARD,
useClass: AuthGuard,
},
{
provide: APP_GUARD,
useClass: RolesGuard,
},
],
})
您还应该从
AuthGuard
中删除 book.controller.ts
,因为它将从应用程序模块执行。