【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)}
}

相关内容

热门资讯

PD-1“四小龙”君实生物,五... 创新药已经走出谷底,且已经迎来阶段性的繁荣。据统计,今年4月初至今,创新药板块的累计涨幅超过了20%...
我国球团矿技术和装备的发展 钢铁冶金2025年07月03日 16:42上海随着我国钢铁行业结构调整优化的需求和绿色低碳高质量的要...
“大金砖合作”彰显更强“南方力... 来源:新新华社里约热内卢7月5日电 题:“大金砖合作”彰显更强“南方力量”新华社记者赵焱 陈威华 周...
23名死亡人员领高龄津贴,官方... 近日,山西省朔州市怀仁市民政局发布关于死亡人员违规领取高龄津贴情况公告。公告称,自该市开展专项整治和...
锁定噪声源头,治理尚未结束,为... 转自:中国环境网“感谢执法大队这么久以来一直跟进处理这个案子!遇到各种困难也不推脱,这份用心太珍贵了...
下半年生猪价格怎么走? 转自:证券时报网2025年上半年,我国生猪市场在供需博弈中呈现“现货曲折走弱、期货宽幅震荡”的格局。...
时隔57年!印度领导人访问阿根... 当地时间7月4日晚,印度总理莫迪抵达阿根廷首都布宜诺斯艾利斯开启对阿国事访问,这是自1968年甘地访...
技能提升与形象管理成毕业生“暑...   学车、变美、健身、学化妆……2025年高考落下帷幕,高三毕业生们迎来了人生中最长、最自由的假期。...
买了公寓后悔死了,酒店式公寓怎... 杭州的商品房成交量一直在上升,几乎都在这波政策红利中迎来了久违的新生,无论是新的还是旧的,还是晚的。...
黄堡镇南寺社区让“身边熟人”变...   社区治理水平关系着居民生活的幸福指数,长期以来,基层社区面临着“管理和服务的人口多,社区工作人员...