【nestjs+mongodb】- 全栈- passport策略的用户登录
创始人
2024-06-01 07:52:28
0

要实现登录模块,首先需要一个auth权限模块去做

auth权限模块

要开发auth用户权限模块

  1. 首先先要有注册用户模块,其中,libs的user模型对应的用户名和密码的定义如下。 其中select: false是为了不向客户端返回密码,尽管我们对其进行散列加密,但还是不要传回客户端尾号。

user.module.ts

作用:主要供auth注册时,需要注入user模型到auth模块上

import { prop, modelOptions, DocumentType } from '@typegoose/typegoose';
import { ApiProperty } from '@nestjs/swagger';
import { hashSync } from 'bcryptjs';export type UserDocument = DocumentType;@modelOptions({schemaOptions: {timestamps: true,},
})
export class User {@ApiProperty({ description: '用户名', example: 'user1' })@prop()username: string;@ApiProperty({ description: '密码', example: 'pass1' })@prop({select: false,get(val) {return val;},set(val) {return val ? hashSync(val) : val;},})password: string;
}

auth.controller.ts

import { Controller, Post, Body, Get, UseGuards, Req } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiProperty, ApiBearerAuth } from '@nestjs/swagger';
import { InjectModel } from 'nestjs-typegoose';
import { User, UserDocument } from '@libs/db/models/user.model';
import { ReturnModelType, DocumentType } from '@typegoose/typegoose';
import { AuthGuard } from '@nestjs/passport';
import { LoginDto } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
import { JwtService } from '@nestjs/jwt';
import { CurrentUser } from './current-user.decorator';@Controller('auth')
@ApiTags('用户')
export class AuthController {constructor(private jwtService: JwtService,@InjectModel(User) private userModel: ReturnModelType,) {}@Post('register')@ApiOperation({ summary: '注册' })async register(@Body() dto: RegisterDto) {const { username, password } = dto;const user = await this.userModel.create({username,password,});return user;}@Post('login')@ApiOperation({ summary: '登录' })@UseGuards(AuthGuard('local'))async login(@Body() dto: LoginDto, @CurrentUser() user: UserDocument) {return {token: this.jwtService.sign(String(user._id)),};}@Get('user')@ApiOperation({ summary: '获取个人信息' })@UseGuards(AuthGuard('jwt'))@ApiBearerAuth()async user(@CurrentUser() user: UserDocument) {return user;}
}

自定义装饰器

有上面的代码可知,我们需要取到jwt token校验后的user属性,因此我们需要封装对应装饰器去取到,由于该currentUser装饰器的逻辑简单,只需要取对应req的user即可

import { createParamDecorator, ExecutionContext } from "@nestjs/common";
import { Request } from "express";export const CurrentUser = createParamDecorator((data, ctx: ExecutionContext) => {const req: Request = ctx.switchToHttp().getRequest()return req.user
})

passport 策略

校验用户名和密码,通过model.findOne找到对应的name

安装对应的包

pnpm i passport-jwt passport passport-local

local.strategy

import { Strategy, IStrategyOptions } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { InjectModel } from 'nestjs-typegoose';
import { User } from '@libs/db/models/user.model';
import { ReturnModelType } from '@typegoose/typegoose';
import { BadRequestException } from '@nestjs/common';
import {compareSync} from 'bcryptjs'export class LocalStrategy extends PassportStrategy(Strategy, 'local') {constructor(@InjectModel(User) private userModel: ReturnModelType,) {super({usernameField: 'username',passwordField: 'password',} as IStrategyOptions);}async validate(username: string, password: string) {const user = await this.userModel.findOne({ username }).select('+password');if (!user) {throw new BadRequestException('用户名不正确');}if (!compareSync(password, user.password)) {throw new BadRequestException('密码不正确')}return user;}
}

小结

用户使用流程,登录时,会在调用登录接口时,用一个守卫guard去拦截用户信息,通过passport去检验用户是否存在在数据库。

auth模块 控制器

auth模块 用于用户登录,使用到了passport策略去进行校验

import { Controller, Post, Body, Get, UseGuards, Req } from '@nestjs/common';
import {ApiTags,ApiOperation,ApiProperty,ApiBearerAuth,
} from '@nestjs/swagger';
import { InjectModel } from 'nestjs-typegoose';
import { User, UserDocument } from '@libs/db/models/user.model';
import { ReturnModelType, DocumentType } from '@typegoose/typegoose';
import { AuthGuard } from '@nestjs/passport';
import { LoginDto } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
import { JwtService } from '@nestjs/jwt';
import { CurrentUser } from './current-user.decorator';@Controller('auth')
@ApiTags('用户')
export class AuthController {constructor(private jwtService: JwtService,@InjectModel(User) private userModel: ReturnModelType,) {}@Post('register')@ApiOperation({ summary: '注册' })async register(@Body() dto: RegisterDto) {const { username, password } = dto;const user = await this.userModel.create({username,password,});return user;}@Post('login')@ApiOperation({ summary: '登录' })@UseGuards(AuthGuard('local'))async login(@Body() dto: LoginDto, @CurrentUser() user: UserDocument) {return {token: this.jwtService.sign(String(user._id)),};}@Get('user')@ApiOperation({ summary: '获取个人信息' })@UseGuards(AuthGuard('jwt'))@ApiBearerAuth()async user(@CurrentUser() user: UserDocument) {return user;}
}

libs/common 通用模块

import { Module, Global } from '@nestjs/common';
import { CommonService } from './common.service';
import { ConfigModule } from '@nestjs/config'
import { DbModule } from '@libs/db';
import {JwtModule} from '@nestjs/jwt'@Global()
@Module({imports: [ConfigModule.forRoot({isGlobal: true}),JwtModule.registerAsync({useFactory(){return {secret: process.env.SECRET}}}),DbModule,],providers: [CommonService],exports: [CommonService, JwtModule],
})
export class CommonModule {}

小结

通过passport策略检验成功后,返回一个jwt配合本地秘钥生成token,供用户调用其他接口时使用,因此我们需要一个jwt策略去

jwt.strategy

import { Strategy, StrategyOptions, ExtractJwt } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { InjectModel } from 'nestjs-typegoose';
import { User } from '@libs/db/models/user.model';
import { ReturnModelType } from '@typegoose/typegoose';export class JwtStrategy extends PassportStrategy(Strategy) {constructor(@InjectModel(User) private userModel: ReturnModelType,) {super({jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),secretOrKey: process.env.SECRET} as StrategyOptions);}async validate(id) {return await this.userModel.findById(id)}
}

相关内容

热门资讯

主角会武功的都市小说 主角会武功的都市小说RT.. YY的。 剧情有意思的。 有知道的介绍几部。谢谢武林高手在校园 名...
初中英语句子 初中英语句子①为什么用it  ②用to  go  to school  可以吗?为什么?有什么区别?...
作家冯唐的作品有哪些 作家冯唐的作品有哪些我想到了一篇震撼的小说故事,何马写的《藏地密码》,那位强巴少爷为了一条叫獒的犬不...
蒙语版的电视剧 蒙语版的电视剧你要是在内蒙呼和浩特的话。有一个内蒙古的蒙语台。会播译成蒙语的电视剧。我们以前上大学时...
羊子分娩的问题 羊子分娩的问题我忘了羊子是什么时候去相亲的,所以怎样知道它是什么时候生小羊子,还有就是应该注意些什么...
什么是儿童互动投影游戏?儿童互... 什么是儿童互动投影游戏?儿童互动投影多少钱?楼主是要加盟吗?这个可以咨询一下智立方互动科技哦,他们是...
张若昀和唐艺昕的绝美爱情到底有... 张若昀和唐艺昕的绝美爱情到底有多甜? 张若昀和唐艺昕可以说是娱乐圈的模范情侣了,两个人自从相爱到结婚...
就算你把天捅个窟窿也有我给你托... 就算你把天捅个窟窿也有我给你托着 什么电视剧生活家。在迹念生活家大结局中老白鼓足勇气,终于追回了程帆...
大笑江湖全集 大笑江湖全集皮皮播放器里就有,可以下个
嵩哥,为了你什么都愿意 嵩哥,为了你什么都愿意 嵩哥,我们会永远支持你!永远爱你!一个人的时候,静静地听着你的歌,深深的体会...
我跟前夫离婚5年多了,当时是他... 我跟前夫离婚5年多了,当时是他外面养小三不回家我就把他拉回来离了可是到底是你儿子啊。你可以考虑和你前...
我是女生,可我的初恋竟然献给了... 我是女生,可我的初恋竟然献给了另外一位女生,怎么会这样?懵懵懂懂的爱情并不是真正的爱情 也看不出什么...
宫锁心玉21集素颜临死前说的是... 宫锁心玉21集素颜临死前说的是什么诗?相见欢(李煜)林花谢了春红,太匆匆,无奈朝来寒雨晚来风。 ...
有个男的对我说喵喵是什么意思 有个男的对我说喵喵是什么意思这个真不知道 你要问那个男的才行,如果是认瞎轮散识的男人可能是开玩笑或者...
城市道路交通规划设计规范最新版... 城市道路交通规划设计规范最新版本是哪年的城市道路交通规划设计规范(GB 50220—95)而道路工程...
冬夜读书示子聿的背景故事 冬夜读书示子聿的背景故事冬夜读书示子聿的背景故事,陆游是在什么情况下作出这首诗的?1、写作背景宋宁宗...
佩恩的本尊在哪 佩恩的本尊在哪佩恩本尊既是长门!本体长门通常都是在雨隐村的、以佩恩六道的形式行动!袭击木叶时本体长门...
在电脑上录制电视节目需要安装些... 在电脑上录制电视节目需要安装些什么东西(软、硬见件)?在电脑上录制电视节目需要安装些什么东西?几乎所...
诛仙里炼血死士和金蝠在那有?具... 诛仙里炼血死士和金蝠在那有?具体位置解答:金瞳妖蝠在3线蝙蝠洞池塘,炼血死士在4线蝙蝠洞桥下,75+...
孙悟空的紧箍咒该不该带 孙悟空的紧箍咒该不该带请快点告诉我(这是辩论题)不该!想要束缚一个人要从心灵上着手!大侠何出此问?该...