身份验证是任何应用程序最重要的方面之一。它通过在授予用户访问应用程序不同部分的访问权限之前验证用户来提高应用程序的安全性。身份验证还使公司能够跟踪有多少人在使用他们的产品。
正确配置身份验证至关重要。事实上,开放 Web 应用程序安全项目 (OWASP) 在其十大 Web 应用程序安全风险列表中确定了识别和身份验证失败。
本教程将演示在 NestJS 中实现 JWT 用户身份验证的分步过程。
跳跃前进:
先决条件
什么是 NestJS?
入门
设置 MongoDB 数据库
创建用户模块
创建用户架构
创建用户服务
创建用户控制器
创建身份验证模块
配置 JWT
创建身份验证服务和控制器
测试应用程序
本教程是一个动手演示。要继续进行,请确保您已安装以下内容:
Node.js v14 及以上
MongoDB
纱线全球安装;使用命令npm install --global yarn
NestJS 是 Node.js 的服务器端应用程序框架,可让您创建可扩展且高效的应用程序。它是用 TypeScript 编写的,并使用 Express.js 构建,这是一个轻量级的框架,它本身就很棒,但缺乏结构。
Nest 支持面向对象编程、函数式编程和函数式反应式编程。如果你想在你的应用程序的后端有很多结构,这个框架是一个很好的选择。
Nest 的语法和结构与前端框架 Angular 相似。它还使用 TypeScript、服务和依赖注入,就像 Angular 一样。Nest 使用模块和控制器,并允许您使用命令行界面为文件创建控制器。
要设置项目,您首先需要使用以下命令全局安装 Nest CLI:
npm i -g @nestjs/cli
安装完成后,创建一个新项目,如下所示:
nest new auth-with-nest
接下来,系统将提示您选择包管理器来安装依赖项。对于这个演示,我们将使用 Yarn。
选择yarn并按Enter键。现在,等待 Yarn 安装运行应用程序所需的所有依赖项。
要设置和连接数据库,请使用以下命令安装 Mongoose 包、bcrypt 和 NestJS 包装器:
npm install --save @nestjs/mongoose @types/bcrypt mongoose bcrypt
现在,更新app.module.ts文件并设置 Mongoose,如下所示:
import { MongooseModule } from '@nestjs/mongoose'; @Module({ imports: [MongooseModule.forRoot('mongodb://localhost/authentication')], })
在上面的代码片段中,我们将 导入MongooseModule到 rootAppModule中。
为了让您的代码保持整洁和井井有条,请通过运行以下命令专门为 NestJS CLI 用户创建一个模块:
nest g module users
上面的代码创建了一个包含users.module.ts文件和app.module.ts更新文件的用户文件夹。
要创建用户架构,users.model.ts请在文件夹中创建一个文件src/users并添加以下代码:
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document } from 'mongoose'; export type UserDocument = User & Document; @Schema() export class User { @Prop() username: string; @Prop() password: string; } export const UserSchema = SchemaFactory.createForClass(User);
在这里,我们用装饰器和装饰器定义了User模式的形状。@Schema()``@Prop()
超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →
Mongoose 会将模式映射到 MongoDB 集合。模式定义了集合文档的形状。
现在,替换user/user.module.ts文件中的代码并userSchema在导入中使用以下代码:
import { Module } from '@nestjs/common'; import { UsersService } from './user.service'; import { UsersController } from './user.controller'; import { MongooseModule } from "@nestjs/mongoose" import { UserSchema } from "./user.model" @Module({ imports: [MongooseModule.forFeature([{ name: "user", schema: UserSchema }])], providers: [UsersService], controllers: [UsersController] }) export class UserModule {}
创建用户架构后,运行以下命令来创建用户服务:
nest g service users
此代码创建一个users.service.ts文件并更新该app.module.ts文件。
注意, 您可以选择手动创建文件和文件夹,但 NestJS CLI 会自动更新必要的文件夹,让您的生活更轻松
现在,将以下代码添加到users.service.ts文件中:
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { User, UserDocument } from './users.model'; @Injectable() export class UsersService { constructor(@InjectModel('user') private readonly userModel: Model<UserDocument>) { } async createUser(username: string, password: string): Promise<User> { return this.userModel.create({ username, password, }); } async getUser(query: object ): Promise<User> { return this.userModel.findOne(query); } }
在这里,我们使用@InjectModel()装饰器userModel将UsersService.
现在让我们创建一个用户控制器来定义 API 路由:
nest g service users
将代码添加到users.controller.ts文件中:
import { Body, Controller, Post, Get, Param } from '@nestjs/common'; import { UsersService } from './users.service'; import { User } from './users.model'; import * as bcrypt from 'bcrypt'; @Controller('auth') export class UsersController { constructor(private readonly usersService: UsersService) { } @Post('/signup') async createUser( @Body('password') password: string, @Body('username') username: string, ): Promise<User> { const saltOrRounds = 10; const hashedPassword = await bcrypt.hash(password, saltOrRounds); const result = await this.usersService.createUser( username, hashedPassword, ); return result; } }
在这里,我们定义了两个 API 路由并使用了我们创建的服务。Windows必备软件全是独立版,56款官方“绿色版”,全都舍不得卸载!我们用来bcrypt散列用户密码。
让我们从创建一个 auth 模块开始,如下所示:
nest g module auth
此命令将创建一个auth带有auth.module.ts文件的新文件夹;它还将更新app.module.ts文件。
现在,让我们实现一个JSON Web 令牌来验证用户进入应用程序。
首先,安装以下依赖项:
npm install --save @nestjs/jwt passport-jwt npm install --save-dev @types/passport-jwt
接下来,创建一个新文件 ,local.auth.ts并添加以下代码:
import { Strategy } from 'passport-local'; import { PassportStrategy } from '@nestjs/passport'; import { Injectable, UnauthorizedException } from '@nestjs/common'; import { AuthService } from './auth.service'; @Injectable() export class LocalStrategy extends PassportStrategy(Strategy) { constructor(private authService: AuthService) { super(); } async validate(username: string, password: string): Promise<any> { const user = await this.authService.validateUser(username, password); if (!user) { throw new UnauthorizedException(); } return user; } }
在这里,我们实施了一个本地护照策略来验证 JSON Web 令牌。由壁纸App,内置所有壁纸资源全部超清免费,超多风格的手机主题任意下!默认情况下,护照本地策略在请求正文中需要username和password属性。
我们还实现了validate()Passport 中间件将调用的方法,以使用适当的特定于策略的参数集来验证用户。
接下来,将 中的代码替换为AuthModule以下内容:
import { Module } from "@nestjs/common" import { UserModule } from "src/user/user.module"; import { AuthService } from "./auth.service" import { PassportModule } from "@nestjs/passport" import { JwtModule } from '@nestjs/jwt'; import { AuthController } from './auth.controller'; import { UsersService } from "src/user/user.service"; import { MongooseModule } from "@nestjs/mongoose" import { UserSchema } from "../user/user.model" import { LocalStrategy } from './local-strategy'; @Module({ imports: [UserModule, PassportModule, JwtModule.register({ secret: 'secretKey', signOptions: { expiresIn: '60s' }, }), MongooseModule.forFeature([{ name: "user", schema: UserSchema }])], providers: [AuthService, UsersService, LocalStrategy], controllers: [AuthController], }) export class AuthModule { }
在这里,我们将PassportModuleandJwtModule导入到导入数组中。然后我们使用该register方法注册 JWT,提供秘密和过期时间。
不要错过来自 LogRocket 的精选时事通讯The Replay
了解LogRocket 的 Galileo 如何消除噪音以主动解决应用程序中的问题
使用 React 的 useEffect优化应用程序的性能
在多个 Node 版本之间切换
了解如何使用 AnimXYZ 为您的 React 应用程序制作动画
探索 Tauri,一个用于构建二进制文件的新框架
比较NestJS 与 Express.js
我们还在UserSchema导入中提供了可用,Office激活神器,在线下载一键激活,VIP会员专业版就是香!并将 theUserService和 our添加LocalStrategy到提供程序数组中。
注意, 出于安全原因,请始终将您的 JWT 密码保存在环境变量中
现在,让我们向应用程序添加身份验证功能。
配置 JWT 和 Passport 后,运行以下命令在文件夹中创建auth.service.ts和auth.controller.ts文件auth:
nest generate service auth nest generate controller auth
接下来,打开auth/auth.service.ts文件并使用以下代码对用户进行身份验证:
import { Injectable, NotAcceptableException } from '@nestjs/common'; import { UsersService } from 'src/user/user.service'; import * as bcrypt from 'bcrypt'; import { JwtService } from '@nestjs/jwt'; @Injectable() export class AuthService { constructor(private readonly usersService: UsersService, private jwtService: JwtService) { } async validateUser(username: string, password: string): Promise<any> { const user = await this.usersService.getUser({ username }); if (!user) return null; const passwordValid = await bcrypt.compare(password, user.password) if (!user) { throw new NotAcceptableException('could not find the user'); } if (user && passwordValid) { return user; } return null; } async login(user: any) { const payload = { username: user.username, sub: user._id }; return { access_token: this.jwtService.sign(payload), }; } }
在这里,我们创建了validateUser方法来检查来自数据库的用户是否user.model匹配来自数据库的用户记录。如果没有匹配,该方法返回一个null值。
我们还创建了一个login方法,该方法使用该jwtService.sign方法validate从我们的LocalStrategy.
现在,将下面的代码片段添加到auth/auth.controller.ts文件中以为用户创建路由login。
import { Controller, Request, Post, UseGuards } from '@nestjs/common'; import { AuthService } from './auth.service'; import { AuthGuard } from '@nestjs/passport'; @Controller() export class AuthController { constructor(private authService: AuthService) { } @UseGuards(AuthGuard('local')) @Post('auth/login') async login(@Request() req) { return this.authService.login(req.user); } }
在这里,我们使用@UseGuards()装饰器在用户请求登录路由时强制执行身份验证。通过AuthGuard该类,我们能够使用该local策略对用户进行身份验证。
现在让我们使用 Postman 测试应用程序。我们将从signup route.
首先,启动应用程序:
npm run start
接下来,打开 Postman 并通过向端点发送 post 请求来测试注册路由。localhost:3000/users/signup.
现在,通过向端点发送发布请求来测试登录端点。localhost:3000/auth/login.
如果username和password存在于数据库中,用户将收到access_token如上图所示。使用access_token,用户将能够访问 API 中受保护的路由。
在本教程中,我们提供了 NestJS 的概述,然后演示了如何在 NestJS API 上实现 JWT 用户身份验证。