Environment: Nest.js, Passport. Js, MongoDB

Note the points that need attention as follows

1 registration

During user registration, passwords need to be hashed. Plaintext passwords cannot be directly saved in the database. When querying users, passwords do not need to be queried and returned to the front end.

Hash using bcrypt

The complete user model is shown below

import { prop, modelOptions } from '@typegoose/typegoose'
import { ApiProperty } from '@nestjs/swagger'
import { hashSync } from 'bcryptjs'

@modelOptions({
    schemaOptions: {
        timestamps: true}})export class User {
    @ApiProperty({ description: 'Username'.example: 'user1'})
    @prop()
    username: string

    @ApiProperty({ description: 'password'.example: 'pass1'})
    @prop({
        select: false,
        get(val){
            return val
        },
        set(val){
            return val ? hashSync(val): val
        }
    })
    password: string
}
Copy the code

2 the login

During login, the server verifies the user name and password and returns a token

Verify using the Passport’s local policy

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('Incorrect username');
        }
        if(! compareSync(password,user.password)){throw new BadRequestException('Incorrect password');
        }
        returnuser; }}Copy the code

Returns the token after a successful login

    @Post('login')
    @ApiOperation({summary: 'login'})
    @UseGuards(AuthGuard('local'))
    async login(@Body() dto: LoginDto, @CurrentUser() user: DocumentType<User>){
        return {
            token: this.jwtService.sign(String(user._id))
        };
    }
Copy the code

3 User Authentication

Verify using Passport’s JWT policy

Step 1: Take out the token

Step 2: Search for the user based on the extracted 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)
    }
}
Copy the code