装饰器和中间件是 NestJS 的基础——这些工具可以让你的生活变得非常简单,也可以让你有点不知所措,具体取决于你如何处理它们。
今天,让我们逐步创建用于用户身份验证的自定义装饰器和中间件,同时保持简单明了。拿起你的咖啡,让我们开始吧!
首先,让我们为用户对象定义一个接口。
这将确保类型安全并让我们的 IDE 保持快乐(谁不喜欢快乐的 IDE?)。
export interface IUser { id: string; name: string; primaryEmail: string; phoneNumber: string | null; countryCode: string | null; dob: Date | null; createdAt: Date; updatedAt?: Date; deletedAt?: Date | null; }
自定义装饰器就像 NestJS 应用程序中的酷孩子。
在这里,我们正在制作一个从请求对象中获取用户元数据的方法。
import { createParamDecorator, ExecutionContext } from '@nestjs/common'; import { IUser } from '../interface/user.interface'; export const UserMetadata = createParamDecorator( (_data: unknown, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return request.user as IUser; }, );
就是这样!现在可以使用此装饰器直接在控制器方法中提取用户信息。
现在,让我们创建一个 AuthGuard 来像虚拟保镖一样保护我们的端点。
import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { verify } from 'jsonwebtoken'; import { Observable } from 'rxjs'; import { IS_PUBLIC_KEY } from '../constant/core'; import { IUser } from '../interface/user.interface'; @Injectable() export class AuthGuard implements CanActivate { constructor( private reflector: Reflector, ) { } canActivate( context: ExecutionContext, ): boolean | Promise<boolean> | Observable<boolean> { const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) { return true; } const request = context.switchToHttp().getRequest(); const headers = request.headers; const token = (headers['authorization'] || '').split(' ')[1]; if (!token) { throw new ForbiddenException('Not Authenticated'); } const jwtOpts = { expiresIn: '1h', // Replace with env vars in real use audience: 'your-audience', algorithm: 'HS256', issuer: 'your-issuer', }; try { const decoded = verify(token, "my-jwt-secret-token", { audience: jwtOpts.audience, issuer: jwtOpts.issuer, }) as { user: IUser }; request.user = decoded.user; return true; } catch (err) { throw new ForbiddenException('Session Expired or Invalid'); } } }
有些路由应该是公共的(例如登录),有些可能是内部的。
让我们为此添加两个简单的装饰器。
import { SetMetadata } from '@nestjs/common'; export const IS_PUBLIC_KEY = 'isPublic'; export const IS_INTERNAL = 'isInternal'; export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); export const Internal = () => SetMetadata(IS_INTERNAL, true);
最后,以下是您如何在控制器中使用所有这些内容。
import { Controller, Get, UseGuards } from '@nestjs/common'; import { UserMetadata } from '../decorators/user.decorator'; import { AuthGuard } from '../guards/auth.guard'; import { Public } from '../decorators/public.decorator'; @Controller('users') export class UserController { @Public() @Get('login') login() { return { message: 'Login endpoint (public)' }; } @UseGuards(AuthGuard) @Get('profile') getProfile(@UserMetadata() user: IUser) { return { message: 'User Profile', user, }; } }
就是这样!您已经创建了自定义装饰器、中间件和元数据装饰器来管理公共路由。
使用这些工具,您可以在 NestJS 中构建安全且有组织的 API。
如果这感觉太多了,请记住 - 即使罗马也不是一天建成的,但您的 API 绝对可以更快地扩展!
随意调整和试验这些片段。
NestJS 的无限可能! ?
我一直在开发一个名为 LiveAPI 的超级方便的工具。
它旨在让开发人员轻松编写 API 文档。
使用LiveAPI,您可以快速生成交互式API文档,允许用户直接从浏览器执行API。
如果您厌倦了为 API 手动创建文档,这个工具可能会让您的生活变得更轻松。
以上是如何在 NestJS 中创建和使用装饰器和中间件的详细内容。更多信息请关注PHP中文网其他相关文章!