Node 后端 框架 Nest js鉴权

  • 使用 nest g res auth去生成restful风格的auth模块,下面是具体操作
nest g res auth
安装基础依赖
{
   
  "name": "auth",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
   
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
   
    "@nestjs/common": "^10.0.0",
    "@nestjs/core": "^10.0.0",
    "@nestjs/jwt": "^10.1.0",
    "@nestjs/mapped-types": "*",
    "@nestjs/passport": "^10.0.0",
    "@nestjs/platform-express": "^10.0.0",
    "@nestjs/typeorm": "^10.0.0",
    "bcryptjs": "^2.4.3",
    "mysql2": "^3.6.0",
    "passport": "^0.6.0",
    "passport-jwt": "^4.0.1",
    "reflect-metadata": "^0.1.13",
    "rxjs": "^7.8.1",
    "typeorm": "^0.3.17"
  },
  "devDependencies": {
   
    "@nestjs/cli": "^10.0.0",
    "@nestjs/schematics": "^10.0.0",
    "@nestjs/testing": "^10.0.0",
    "@types/bcryptjs": "^2.4.2",
    "@types/express": "^4.17.17",
    "@types/jest": "^29.5.2",
    "@types/node": "^20.3.1",
    "@types/passport-jwt": "^3.0.9",
    "@types/supertest": "^2.0.12",
    "@typescript-eslint/eslint-plugin": "^5.59.11",
    "@typescript-eslint/parser": "^5.59.11",
    "eslint": "^8.42.0",
    "eslint-config-prettier": "^8.8.0",
    "eslint-plugin-prettier": "^4.2.1",
    "jest": "^29.5.0",
    "prettier": "^2.8.8",
    "source-map-support": "^0.5.21",
    "supertest": "^6.3.3",
    "ts-jest": "^29.1.0",
    "ts-loader": "^9.4.3",
    "ts-node": "^10.9.1",
    "tsconfig-paths": "^4.2.0",
    "typescript": "^5.1.3"
  },
  "jest": {
   
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
   
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

  • 执行命令 yarn install 安装 依赖
配置 基础信息

在app.modules 中去配置数据库连接信息

import {
    Module } from '@nestjs/common';
import {
    AppController } from './app.controller';
import {
    AppService } from './app.service';
import {
    AuthModule } from './auth/auth.module';
import {
    TypeOrmModule } from '@nestjs/typeorm';
import {
    APP_GUARD } from '@nestjs/core';
import {
    JwtAuthGuard } from './auth/jwt-auth.grard';

@Module({
   
  imports: [AuthModule, TypeOrmModule.forRoot({
   
    type: 'mysql', // 数据库类型
    host: 'localhost', // 主机名
    port: 3306, // 端口
    username: 'root', // 用户名
    password: 'root', // 密码
    database: 'auth', // 数据库名称
    synchronize: true,
    retryDelay: 500, //重试连接数据库间隔
    retryAttempts: 10,//重试连接数据库的次数
    autoLoadEntities: true, //如果为true,将自动加载实体 forFeature()方法注册的每个实体都将自动添加到配置对象的实体数组中
  })],
  controllers: [AppController],
  // 注册为全局守卫
  providers: [AppService, {
   
    provide: APP_GUARD,
    useClass: JwtAuthGuard
  }],
})
export class AppModule {
    }

接着在 auth.entity.ts文件中去写关于用户表的配置,我这里就做三个字段id,username,password

  • 定义密钥有效时间
export const jwtConstants = {
   
    secret: "leeKey", // 密钥
    expiresIn: "60s" // token有效时间  
}
  • 配置AUTH 的 策略
import {
    Injectable } from "@nestjs/common";
import {
    PassportStrategy } from "@nestjs/passport";
import {
    ExtractJwt, Strategy } from "passport-jwt";
import {
    jwtConstants } from "./constants";


interface JwtPayload {
   
    username: string
}

@Injectable()
// 验证请求头中的token
export class JwtAuthStrategy extends PassportStrategy(Strategy, "jwt") {
   
    constructor() {
   
        super(
        {
   
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: false,
            secretOrKey: jwtConstants.secret
        }
        )
    }

    async validate(payload: JwtPayload) {
   
        console.log(payload.username);
        const {
    username } = payload
        return {
   
            username
        }
    }
}
  • 在auth.modules 完成jwt 配置 引入密钥配置
import {
    Module } from '@nestjs/common';
import {
    AuthService } from './auth.service';
import {
    AuthController } from './auth.controller';
import {
    TypeOrmModule } from '@nestjs/typeorm';
import {
    NV_Users } from './entities/auth.entity';
import {
    JwtModule } from '@nestjs/jwt';
import {
    jwtConstants } from "./constants"
import {
    JwtAuthStrategy } from "./jwt-auth.strategy"


@Module({
   
  imports: [TypeOrmModule.forFeature([NV_Users]), JwtModule.register({
   
    secret: jwtConstants.secret,
    signOptions: {
    expiresIn: jwtConstants.expiresIn }
  })],
  controllers: [AuthController],
  providers: [AuthService, JwtAuthStrategy]
})
export class AuthModule {
    }

  • 创建表
CREATE TABLE NV_Users (
  id int NOT NULL AUTO_INCREMENT,
  username varchar(255) NOT NULL,
  password varchar(255) NOT NULL,
  PRIMARY KEY (id)
);
  • 配置实体类
import {
    Column, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class NV_Users {
   

    @PrimaryGeneratedColumn()
    id:number

    @Column()
    username:string

    @Column()
    password:string
}

  • 业务层完成基础的注册逻辑
import {
    BadRequestException, Injectable } from '@nestjs/common';
import {
    CreateAuthDto } from './dto/create-auth.dto';
import {
    NV_Users } from './entities/auth.entity';
import {
    Repository } from 'typeorm';
import {
    InjectRepository } from '@nestjs/typeorm';
import * as bcryptjs from "bcryptjs"
import {
    JwtService } from "@nestjs/jwt"


@Injectable()
export class AuthService {
   
    constructor(
        @InjectRepository(NV_Users) private readonly user: Repository<NV_Users>,
        private readonly JwtService: JwtService
    ) {
    }
    // 注册
    async signup(signupData: CreateAuthDto) {
   
        
        const findUser = await this.user.findOne({
   
            where: {
    username: signupData.username }
        })
        if (findUser && findUser.username === signupData.username) return "用户已存在"
        // 对密码进行加密处理
        signupData.password = bcryptjs.hashSync(signupData.password, 10)
        await this.user.save(signupData)
        return "注册成功"
    }

    // 登录
    async login(loginData: CreateAuthDto) {
   
        const findUser = await this.user.findOne({
   
            where: {
    username: loginData.username }
        })
        // 没有找到
        if (!findUser) return new BadRequestException("用户不存在")

        // 找到了对比密码
        const compareRes: boolean = bcryptjs.compareSync(loginData.password, findUser.password)
        // 密码不正确
        if (!compareRes) return new BadRequestException("密码不正确")
        const payload = {
    username: findUser.username }

        return {
   
            access_token: this.JwtService.sign(payload),
            msg: "登录成功"
        }
    }
}

  • 定义请求的dto
export class CreateAuthDto {
   
    username: string
    password: string
}

  • 通过注解进行控制 是否需要授权
import {
    SetMetadata } from "@nestjs/common";

export const IS_PUBLIC_KEY = 'isPublic'
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
  • 请求层
import {
    Controller, Post, Body } from '@nestjs/common';
import {
    AuthService } from './auth.service';
import {
    CreateAuthDto } from './dto/create-auth.dto';
import {
    Public } from 'src/common/public.decorator';

@Controller('auth')
export class AuthController {
   
  constructor(private readonly authService: AuthService) {
    }

  // 注册
  // @Public()
  @Post("/signup")
  signup(@Body() signupData: CreateAuthDto) {
   
    return this.authService.signup(signupData)
  }

  // 登录
  @Public()
  @Post("/login")
  login(@Body() loginData: CreateAuthDto) {
   
    return this.authService.login(loginData)
  }
}

  • 配置拦截守卫
import {
    ExecutionContext, Injectable } from "@nestjs/common";
import {
    Reflector } from '@nestjs/core';
import {
    AuthGuard } from '@nestjs/passport';
import {
    Observable } from "rxjs";
import {
    IS_PUBLIC_KEY } from "src/common/public.decorator";

@Injectable()
export class JwtAuthGuard extends AuthGuard("jwt") {
   
    constructor(private reflector: Reflector) {
   
        super()
    }

    canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
   
        const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
            context.getHandler(),
            context.getClass()
        ])
        console.log(isPublic, "isPublic");
        if (isPublic) return true
        return super.canActivate(context)
    }
}
测试
  1. 获取token

image.png

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-09 02:48:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-09 02:48:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-09 02:48:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-09 02:48:01       20 阅读

热门阅读

  1. postgresql-effective_cache_size参数详解

    2023-12-09 02:48:01       32 阅读
  2. leetcode - 2264. Largest 3-Same-Digit Number in String

    2023-12-09 02:48:01       34 阅读
  3. 实例分割网络:Mask RCNN

    2023-12-09 02:48:01       38 阅读
  4. nodejs fs模块

    2023-12-09 02:48:01       47 阅读
  5. C/C++ 实现枚举网上邻居信息

    2023-12-09 02:48:01       31 阅读
  6. unix dgram通信

    2023-12-09 02:48:01       31 阅读
  7. 3-Mybatis

    3-Mybatis

    2023-12-09 02:48:01      40 阅读