🔥🔥超简单!!nestJS+jwt实现登录

创建项目

1、在命令行输入nest new jwt-login,jwt-login是项目名。回车键继续。

2、选择包管理工具,这里我选择npm,回车键继续

此时就开始安装依赖包了,这里要等一等

进入项目就会看到这样的目录
3、控制台输入npm run start:dev启动项目, 出现这样的情况就是启动成功了。

端口号默认是3000,在浏览器输入http://localhost:3000, 出现hello word就是启动成功了

实现登录功能

创建auth模块

在浏览器输入nest g res auth --no-spec

默认选择rest api 一直回车,此时目录出现了auth文件夹

数据传输对象(dto)

在auth/dto/中将创建login-auth.dto.ts,并添加如下代码:

ts 复制代码
export class LoginAuthDto {
  username: string;
  password: string;
}

显然所谓的数据传输对象就是前端传递过来的参数对象,这里前端需要传递username和password,那么为什么要创建这个数据传输对象呢,继续往下看。

安装依赖包:npm i --save class-validator class-transformer,接着将login-auth.dto.ts中的代码修改如下:

ts 复制代码
import { IsNotEmpty, Length } from 'class-validator';
export class LoginAuthDto {
  @IsNotEmpty({ message: 'Username is required' })
  username: string;

  @IsNotEmpty({ message: 'Password is required' })
  @Length(6, 20, { message: 'Password must be between 6 and 20 characters' })
  password: string;
}

以上代码中增加了两个装饰器,很显然一个是@IsNotEmpty的装饰器是校验该项不能为空的,@Leng是来限制参数的长度的。这个dto对象该如何用呢,后面继续会讲到。

在main.ts中新增如下代码:

ts 复制代码
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();

以上新增的代码意思是全局启用管道验证,具体功效后面会讲到。

创建登录接口

在auth/auth.service.ts中将原用自动生成的函数删掉,新增login函数:

ts 复制代码
import { Body, Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LoginAuthDto } from './dto/login-auth.dto';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}
  @Post('login')
  login(@Body() loginAuthDto: LoginAuthDto) {
    return loginAuthDto;
  }
}

注意login函数中的参数使用了之前创建的LoginAuthDto对象,在这里可以对前端传来的参数进行校验。

在apifox里面进行测试:

username设置为空的情况下请求会返回我们之前定义的报错信息,如果把username补上去就是这样的:

可见已经跑通了。这就是dto的魅力所在,可以很简单的实现参数的校验。

jwt

配置jwt

一般来说正常的登录逻辑是前端传递过来username和password后端生成token返回给前端,前端之后在请求头里面带上token。

安装依赖包:npm install --save @nestjs/jwt。在app.module.ts中引入配置jwt:

ts 复制代码
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { JwtModule } from '@nestjs/jwt';

@Module({
  imports: [
    AuthModule,
    JwtModule.register({
      global: true,
      secret: 'xiaosong',
      signOptions: { expiresIn: '7d' },
    }),
  ],

  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

global: 将JwtModule设置成全局模块,secret:密钥,用于JWT令牌的签名和验证,signOptions: 设置token的过期时间为7天。

生成token

在auht/auth.service.ts中增加login函数,并且将自动生成的代码删除掉:

ts 复制代码
import { HttpException, Injectable } from '@nestjs/common';
import { LoginAuthDto } from './dto/login-auth.dto';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(private readonly jwtService: JwtService) {}
  login(loginAuthDto: LoginAuthDto) {
    const user = {
      id: 1,
      username: 'xiaosong',
      password: '123123',
    };

    if (
      loginAuthDto.username !== user.username ||
      loginAuthDto.password !== user.password
    ) {
      throw new HttpException('用户名或密码错误', 401);
    }

    return {
      token: this.jwtService.sign({
        id: user.id,
        username: user.username,
      }),
    };
  }
}

以上代码看似很多其实很简单,user对象模拟的数据库,存储了用户名、密码、id,当username和password有一处不对的时候抛出异常否则就使用sign生成token,并且token里面携带的是id和username。注意constructor构造函数中是依赖注入,将jwtService这个对象注入进来。

在auth.controller.ts中的login函数中将代码修改一下:

ts 复制代码
import { Body, Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LoginAuthDto } from './dto/login-auth.dto';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}
  @Post('login')
  login(@Body() loginAuthDto: LoginAuthDto) {
    return this.authService.login(loginAuthDto);
  }
}

在apifox里测试一下,先试一试密码不正确的情况: 看到返回了报错信息

再次试一下都正确的情况:

ok,可以看到返回token了

token校验

创建守卫

生成token了但是不进行校验就是虚空的token,这里要创建一个守卫进行拦截

执行指令:nest g gu login 创建一个守卫,在login/login.gurad.ts中增加如下代码

ts 复制代码
import {
  CanActivate,
  ExecutionContext,
  HttpException,
  Injectable,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { Request } from 'express';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class LoginGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request: Request = context.switchToHttp().getRequest();
    const token = request.headers.authorization;

    try {
      this.jwtService.verify(token, {
        secret: 'xiaosong',
      });
    } catch (error) {
      throw new HttpException('token失效', 401);
    }

    return true;
  }
}

以上代码看似十分的复杂,其实核心代码如下:

  • context.switchToHttp().getRequest();:获取request对象
  • request.headers.authorization;:获取token
  • this.jwtService.verify(token, {secret: 'xiaosong',});:token校验

使用守卫

在auth.controller.ts中随便加一个接口

以上代码的 @UseGuards(LoginGuard)是使用创建的login守卫

在apifox里面测试一下:

可见报错了,守卫生效了

先登录获取token,在请求头加上token再试一下:

ok,请求通过了,可见我们的守卫也是十分的好用的。至此jwt机制的登录已经完成了。

相关推荐
有梦想的刺儿3 分钟前
webWorker基本用法
前端·javascript·vue.js
cy玩具24 分钟前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
清灵xmf1 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test2 小时前
js下载excel示例demo
前端·javascript·excel
Yaml42 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo2 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v2 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript