环境:Nest.js、Passport.js、MongoDB
将需要注意的地方记录如下
1 注册
用户注册时,密码需要散列,不能直接将明文密码保存进数据库,而在查询用户时,不需要将用户密码查询出来返回前端。
使用bcrypt进行散列
完整的用户模型如下
import { prop, modelOptions } from '@typegoose/typegoose'
import { ApiProperty } from '@nestjs/swagger'
import { hashSync } from 'bcryptjs'
@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
}
2 登录
登录时服务端进行用户名和密码的校验,并返回token
使用Passport的local策略进行校验
import { Strategy, IStrategyOptions } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport'
import { StrategyOptions } from 'passport-jwt';
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<typeof User>
){
super({
usernameField: 'username',
passwordField: 'password'
} as IStrategyOptions)
}
async validate(username: string, password: string){
const user = await this.userModel.findOne({username: username}).select('+password');
if(!user) {
throw new BadRequestException('用户名不正确');
}
if(!compareSync(password,user.password)){
throw new BadRequestException('密码不正确');
}
return user;
}
}
登录成功之后返回token
@Post('login')
@ApiOperation({summary: '登录'})
@UseGuards(AuthGuard('local'))
async login(@Body() dto: LoginDto, @CurrentUser() user: DocumentType<User>){
return {
token: this.jwtService.sign(String(user._id))
};
}
3 用户验证
使用Passport的jwt策略进行验证
第一步:取出token
第二步:根据取出的id查找对应的用户
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';
import { BadRequestException } from '@nestjs/common';
import { compareSync } from 'bcryptjs'
export class JwtStrategy extends PassportStrategy(Strategy,'jwt'){
constructor(
@InjectModel(User) private userModel: ReturnModelType<typeof User>
){
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.SECRET
} as StrategyOptions)
}
async validate(id){
return await this.userModel.findById(id)
}
}