NestJS简明教程——安全

📅 2026/8/1 14:48:52
NestJS简明教程——安全
登录和注册(代码示例)需要安装的依赖pnpmaddnestjs/jwt nestjs/throttler helmetauth.service.tsimport{ConflictException,Injectable,UnauthorizedException,}fromnestjs/common;import{UsersService}from../users/users.service;import*asbcryptfrombcrypt;import{SignUpDto}from./dto/sign-up.dto;import{SignInDto}from./dto/sign-in.dto;import{NotFoundError}frommikro-orm/core;import{JwtService}fromnestjs/jwt;Injectable()exportclassAuthService{constructor(privatereadonlyusersService:UsersService,privatereadonlyjwtService:JwtService,){}asyncgenerateToken(user:any):Promise{access_token:string}{constpayload{email:user.email,sub:user.id};return{access_token:awaitthis.jwtService.signAsync(payload),};}asyncsignUp(signUpDto:SignUpDto):Promiseany{const{email,name,password}signUpDto;constuserawaitthis.usersService.findOne(email);if(user){thrownewConflictException(User already exists);}consthashedPasswordawaitbcrypt.hash(password,10);awaitthis.usersService.create({email,name,password:hashedPassword});returnawaitthis.usersService.findOne(email);}asyncsignIn(signInDto:SignInDto):Promiseany{const{email,password}signInDto;constuserawaitthis.usersService.findOne(email);if(!user){thrownewNotFoundError(User not found);}constisPasswordValidawaitbcrypt.compare(password,user.password);if(!isPasswordValid){thrownewUnauthorizedException(Invalid password);}consttokenawaitthis.generateToken(user);return{user,token};}}auth.controller.tsimport{Controller}fromnestjs/common;import{AuthService}from./auth.service;import{Post,Body}fromnestjs/common;import{SignUpDto}from./dto/sign-up.dto;import{SignInDto}from./dto/sign-in.dto;import{Public}from./decorator/public.decorator;Controller(auth)exportclassAuthController{constructor(privatereadonlyauthService:AuthService){}Post(register)Public()asyncsignUp(Body()signUpDto:SignUpDto):Promiseany{returnthis.authService.signUp(signUpDto);}Post(login)Public()asyncsignIn(Body()signInDto:SignInDto):Promiseany{returnthis.authService.signIn(signInDto);}}auth.module.tsimport{Module}fromnestjs/common;import{AuthService}from./auth.service;import{AuthController}from./auth.controller;import{UsersModule}from../users/users.module;import{JwtModule}fromnestjs/jwt;import{APP_GUARD}fromnestjs/core;import{AuthGuard}from./auth.guard;Module({imports:[UsersModule,JwtModule.register({secret:process.env.JWT_SECRET,signOptions:{expiresIn:1h,algorithm:HS256},}),],providers:[AuthService,{provide:APP_GUARD,useClass:AuthGuard,},],controllers:[AuthController],})exportclassAuthModule{}JWTauth.guard.tsnest g guard auth/auth --no-spec--flatimport{CanActivate,ExecutionContext,Injectable}fromnestjs/common;import{UnauthorizedException}fromnestjs/common;import{JwtService}fromnestjs/jwt;import{Reflector}fromnestjs/core;import{IS_PUBLIC_KEY}from./decorator/public.decorator;Injectable()exportclassAuthGuardimplementsCanActivate{constructor(privatereadonlyjwtService:JwtService,privatereflector:Reflector,){}privateextractTokenFromHeader(request:any):string|undefined{const[type,token]request.headers.authorization?.split( )??[];returntypeBearer?token:undefined;}asynccanActivate(context:ExecutionContext):Promiseboolean{constisPublicthis.reflector.getAllAndOverrideboolean(IS_PUBLIC_KEY,[context.getHandler(),]);if(isPublic){// See this conditionreturntrue;}// get the request object from the execution contextconstrequestcontext.switchToHttp().getRequest();consttokenthis.extractTokenFromHeader(request);if(!token){thrownewUnauthorizedException(No token provided);}// verify the token using the JwtServicetry{constpayloadawaitthis.jwtService.verifyAsync(token);request[user]payload;}catch(error){thrownewUnauthorizedException(Invalid token);}returntrue;}}public.decorator.tsnest g decorator auth/decorator/public--flatimport{SetMetadata}fromnestjs/common;exportconstIS_PUBLIC_KEYisPublic;exportconstPublic()SetMetadata(IS_PUBLIC_KEY,true);限流app.module.tsimport{ThrottlerModule}fromnestjs/throttler;importthrottlerConfigfrom./common/config/c;ThrottlerModule.forRoot(throttlerConfig)throttler.config.tsexport default [ { name: short, ttl: 1000, limit: 3, }, { name: medium, ttl: 10000, limit: 20, }, { name: long, ttl: 60000, limit: 100, }, ];其他helmetmain.ts// 加入 Helmet 中间件以增强安全性app.use(helmet());