Function Description:

  1. The client uses the user name and password to log in. After the login succeeds, the server sends the JWT message.
  2. The client carries the JWT in the header to access the server. The server authenticates the JWT carried by the client.

Initialize the project

Create project and initialize User, Auth module, terminal

# New NestJS project: Auth-jwt nest new auth-jwt # AuthModule cd auth-jwt nest g module auth nest g service auth nest g controller auth nest g module user nest g service user nest g controller userCopy the code

Engineering structure:

├ ─ ─ nest - cli. Json ├ ─ ─ package. The json ├ ─ ─ package - lock. Json ├ ─ ─ the README. Md ├ ─ ─ the SRC │ ├ ─ ─ app. The controller. The spec. The ts │ ├ ─ ─ │ ├── Auth │ ├─ Auth │ ├─ Auth │ ├.Controll.spec Auth. Controller. Ts │ │ ├ ─ ─ auth. The module. The ts │ │ └ ─ ─ auth. Service. The ts │ ├ ─ ─ main. Ts │ └ ─ ─ the user │ ├ ─ ─ the user. The controller. The ts │ ├ ─ ─ the user. The module. Ts │ └ ─ ─ the user. The service. The ts ├ ─ ─ the test │ ├ ─ ─ app. E2e - spec. Ts │ └ ─ ─ jest - e2e. Json ├ ─ ─ tsconfig. Build. The json └ ─ ─ tsconfig.jsonCopy the code

User Module

  1. Obtain a user by user name.
  2. Get user list;
  3. Export User Service for Auth Service reference;

The user. The entity. Ts:

export interface UserEntity {
  id: number;
  username: string; password? :string;
}
Copy the code

User. Service. Ts:

import { Injectable } from '@nestjs/common';
import { UserEntity } from './user.entity';

@Injectable()
export class UserService {
  private readonly users: Array<UserEntity>;

  constructor() {
    this.users = [
      { id: 1, username: 'admin', password: 'admin' },
      { id: 2, username: 'tester', password: 'tester' },
    ];
  }

  /**
   * find user by username
   * @param username
   */
  async find(username: string): Promise<UserEntity> {
    const user = this.users.find((user) => user.username === username);
    if (user) return user;
    else return null;
  }

  /**
   * list all users
   */
  async listAll(): Promise<Array<UserEntity>> {
    return this.users.map((user) => {
      const { password, ...info } = user;
      return info;
    });
  }
}
Copy the code

User. Controller. Ts:

import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';
import { UserEntity } from './user.entity';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {
    this.userService = userService;
  }

  @Get(a)async list(): Promise<Array<UserEntity>> {
    return this.userService.listAll(); }}Copy the code

Export UserService, user.module.ts from User Module

import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';

@Module({
  providers: [UserService],
  controllers: [UserController],
  exports: [UserService],
})
export class UserModule {}
Copy the code

Auth Module to achieve user login

Passport, passport-local, @nestjs/passport, @types/passport-local, terminal

npm i passport passport-local @nestjs/passport
npm i @types/passport-local -D
Copy the code

Account and password authentication policies are implemented

AuthService implements user identity authentication

Auth.service. ts, user name and password authentication:

import { Injectable } from '@nestjs/common';
import { UserService } from '.. /user/user.service';
import { UserEntity } from '.. /user/user.entity';

@Injectable(a)export class AuthService {
  constructor(private readonly userService: UserService) {
    this.userService = userService;
  }

  /**
   * validate user name and password
   * @param username
   * @param password* /
  async validate(username: string.password: string) :Promise<UserEntity> {
    const user = await this.userService.find(username);
    // Note: The actual password processing should be through encryption measures
    if (user && user.password === password) {
      const{ password, ... userInfo } = user;return userInfo;
    } else {
      return null; }}}Copy the code

LocalStrategy: implements account and password authentication policies.

Create local.strategy.ts in auth directory:

import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-local';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UserEntity } from '.. /user/user.entity';
import { AuthService } from './auth.service';

@Injectable(a)export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super(a);this.authService = authService;
  }

  async validate(username: string.password: string) :Promise<UserEntity> {
    const user = await this.authService.validate(username, password);
    if (user) return user;
    else throw new UnauthorizedException('incorrect username or password'); }}Copy the code

The validate method is the default implementation of user authentication, which is automatically called by the passport-local guard.

User login API

The Login API is implemented in the AuthController using the Passport -local guard. Auth. Controller. Ts:

import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { UserEntity } from '.. /user/user.entity';
import { AuthGuard } from '@nestjs/passport';

@Controller('auth')
export class AuthController {
  @UseGuards(AuthGuard('local'))
  @Post('/login')
  async login(@Request() request): Promise<UserEntity> {
    returnrequest.user; }}Copy the code

@useGuards (AuthGuard(‘local’)) will extract username and password from body, then call validate method in LocalStrategy, and assign User information to Request.user if authenticated.

Auth. Module. Ts:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { PassportModule } from '@nestjs/passport';
import { UserModule } from '.. /user/user.module';
import { LocalStrategy } from './local.strategy';

@Module({
  imports: [UserModule, PassportModule],
  providers: [AuthService, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule {}
Copy the code

NPM run start to start the service, using a POST request to http://127.0.0.1:3000/auth/login, if the user name and password is correct, get user information, otherwise the response code is 401. The curl command is as follows:

The curl -x POST http://127.0.0.1:3000/auth/login - d'{"username": "admin", "password": "123456"}' -H "Content-Type: application/json"

{"statusCode": 401,"message":"incorrect username or password"."error":"Unauthorized"}
Copy the code

JWT Strategy implementation

At this point, the user login function is completed using the Local Strategy user authentication guard. Now let’s implement:

  1. After the user logs in successfully, the access_token is delivered.
  2. The User List service uses JWT authentication.

Install dependencies

Terminal:

npm i passport-jwt @nestjs/jwt npm i @types/passport-jwt -D

Rewrite login. The login succeeds in delivering access_token

Auth.service. ts add login method:

import { Injectable } from '@nestjs/common';
import { UserService } from '.. /user/user.service';
import { UserEntity } from '.. /user/user.entity';
import { JwtService } from '@nestjs/jwt';
import { TokenEntity } from './token.entity';

@Injectable(a)export class AuthService {
  private readonly userService: UserService;
  private readonly jwtService: JwtService;
  constructor(userService: UserService, jwtService: JwtService) {
    this.userService = userService;
    this.jwtService = jwtService;
  }

  /**
   * validate user name and password
   * @param username
   * @param password* /
  async validate(username: string.password: string) :Promise<UserEntity> {
    const user = await this.userService.find(username);
    // Note: The actual password processing should be through encryption measures
    if (user && user.password === password) {
      const{ password, ... userInfo } = user;return userInfo;
    } else {
      return null; }}/**
   * user login
   * @param user* /
  async login(user: UserEntity): Promise<TokenEntity> {
    const { id, username } = user;
    return {
      token: this.jwtService.sign({ username, sub: id }), }; }}Copy the code

Auth. Controller. Ts:

import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { TokenEntity } from './token.entity';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {
    this.authService = authService;
  }
  @UseGuards(AuthGuard('local'))
  @Post('/login')
  async login(@Request() request): Promise<TokenEntity> {
    return this.authService.login(request.user); }}Copy the code

Register JwtModule in AuthModule

Create jwt.contants.ts under auth:

export const jwtContants = {
  secret: 'json_web_token_secret_key'};Copy the code

Register JwtModule, auth.module.ts:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { PassportModule } from '@nestjs/passport';
import { UserModule } from '.. /user/user.module';
import { LocalStrategy } from './local.strategy';
import { JwtModule } from '@nestjs/jwt';
import { jwtContants } from './jwt.contants';

@Module({
  imports: [
    UserModule,
    PassportModule,
    JwtModule.register({
      secret: jwtContants.secret,
    }),
  ],
  providers: [AuthService, LocalStrategy],
  controllers: [AuthController],
})
export class AuthModule {}
Copy the code

Start the service, access the login service, and return the token after the authentication is successful:

The curl -x POST http://127.0.0.1:3000/auth/login - d '{" username ":" admin ", "password" : "admin"}' - H "content-type: application/json" {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwic3ViIjoxLCJpYXQiOjE2MDYxNDQwMjF9.IIOMnGgjMmaq VB4RhNGBxS_rEKuSLsr40yG_ooTuFVU"}Copy the code

JWT access_token certification

Create jwt.strategy.ts under auth:

import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { jwtContants } from './jwt.contants';
import { UserEntity } from '.. /user/user.entity';

@Injectable(a)export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      // Get the request header token value
      jwtFromRequest: ExtractJwt.fromHeader('token'),
      secretOrKey: jwtContants.secret,
    });
  }

  async validate(payload: any) :Promise<UserEntity> {
    // Payload: Decoded result of jWt-passport authentication JWT
    return { username: payload.username, id: payload.sub }; }}Copy the code

Auth. Module. Ts:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { PassportModule } from '@nestjs/passport';
import { UserModule } from '.. /user/user.module';
import { LocalStrategy } from './local.strategy';
import { JwtModule } from '@nestjs/jwt';
import { jwtContants } from './jwt.contants';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [
    UserModule,
    PassportModule,
    JwtModule.register({
      secret: jwtContants.secret,
    }),
  ],
  providers: [AuthService, LocalStrategy, JwtStrategy],
  controllers: [AuthController],
})
export class AuthModule {}
Copy the code

User.controller. ts adds JWT authentication guard:

import { Controller, Get, UseGuards } from '@nestjs/common';
import { UserService } from './user.service';
import { UserEntity } from './user.entity';
import { AuthGuard } from '@nestjs/passport';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {
    this.userService = userService;
  }

  @UseGuards(AuthGuard('jwt'))
  @Get(a)async list(): Promise<Array<UserEntity>> {
    return this.userService.listAll(); }}Copy the code

Start the service, visit http://127.0.0.1:3000/user, token authentication through will receive user list:

The curl http://127.0.0.1:3000/user - H "token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwic3ViIjoxLCJpYXQiOjE2MDYxODA4MjR9.y9xt_rn6nORS5MEU18MeNB 0 brnghvzlxe7saynkz0ky "# # returns [{" id" : 1, "username" : "admin"}, {" id ": 2," username ":" tester "}]Copy the code
  1. Demo project source github.com/louie-001/n…
  2. NestJS official nestjs.com/.