nest框架的token登录,以及token校验

1.搭建项目

  • 项目初始化:
npm i -g @nestjs/cli
nest new project-name


 

  • 在终端下执行这四个命令,生成两个新模块:
nest g module auth 
nest g service auth
nest g module users 
nest g service users
  •  然后把这三个文件删掉,是没有用的:

UserModule

编写 UsersService:

import { Injectable } from '@nestjs/common';

interface User {
    userId: number;
    username: string;
    password: string;
}

@Injectable()
export class UsersService {
    private readonly users: User[];

    constructor() {
        // 这里把用户列表写死了. 在真正的应用程序中,用户列表应该从数据库获取
        this.users = [
            {
                userId: 1,
                username: 'john',
                password: 'riddle',
            },
            {
                userId: 2,
                username: 'chris',
                password: 'secret',
            },
            {
                userId: 3,
                username: 'maria',
                password: 'guess',
            },
        ];
    }

    async findOne(username: string) {
        return this.users.find((user) => user.username === username);
    }
}

在 UsersModule 中,将 UsersService 导出,供其他模块使用:

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';

@Module({
    providers: [UsersService],
    exports: [UsersService], // 导出 UsersService
})
export class UsersModule {}

AuthModule

在 AuthModule 中导入 UserModule:

import { Module } from '@nestjs/common';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';

@Module({
    imports: [UsersModule], // 导入 UsersModule
    providers: [AuthService],
})
export class AuthModule {}

编写 AuthService:

import { Injectable } from '@nestjs/common';
import { UsersService } from 'src/users/users.service';

@Injectable()
export class AuthService {
    constructor(private readonly usersService: UsersService) {}

    /* 检查用户是否已存在 + 校验密码 */
    async validateUser(username: string, pwd: string) {
        const user = await this.usersService.findOne(username); // 获取用户
        if (user && user.password === pwd) {
            const { password, ...result } = user; // 剔除 password
            return result; // 返回用户信息
        }
        return null; // 用户不存在 / 密码错误
    }
}

2.本地策略(这一步还不是jwt,这里只是做登录认证)

在终端上执行这两行代码:
npm i @nestjs/passport passport passport-local
npm i -D @types/passport-local

auth 目录下新增编写本地策略的配置文件 local.strategy.ts

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

@Injectable() // 通过 PassportStrategy 使用 local 策略
export class LocalStrategy extends PassportStrategy(Strategy) {
    constructor(private readonly authService: AuthService) {
        super();
    }

    async validate(username: string, password: string) {
        const user = await this.authService.validateUser(username, password);
        if (!user) {
            throw new UnauthorizedException(); // 返回 '未授权' 错误 (401)
        }
        return user; // 返回用户信息
    }
}

配置 AuthModule 来使用刚才定义的 Passport 特性:

import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport/dist';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';

@Module({
    imports: [UsersModule, PassportModule], // 引入 PassportModule
    providers: [AuthService, LocalStrategy], // 注册 LocalStrategy
})
export class AuthModule {}

登录测试

现在就可以实现一个简单的 /login 路由,并应用内置的守卫来启动 Passport-local 流

import { Controller, Req, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport/dist/auth.guard';
import { Request } from 'express';

@Controller()
export class AppController {
    @UseGuards(AuthGuard('local')) // 启用本地策略
    @Post('login')
    async getHello(@Req() request: Request) {
        // Passport 会根据 validate() 方法的返回值创建一个 user 对象
        // 并以 req.user 的形式分配给请求对象
        return request.user;
    }
}

现在的项目结构:

启动项目测试:

代码说明:

        加入这个注解 @UseGuards(AuthGuard('local')) // 启用本地策略,那会在请求 '/login' 的时候,框架会先去执行 继承了 PassportStrategy 这个类的 validate方法

        注意:如果这里没有写,那就是默认 local


PassportStrategy类的 本地策略 里面的 validate 方法的参数我个人是认为可变的,但是没实现出来,validate 方法完成之后,会把结果放到 request.user 里面

3.token策略

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

 在 AuthModule 中引入 JwtModule:

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport/dist';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';

@Module({
    imports: [UsersModule, PassportModule, JwtModule], // 引入 JwtModule
    providers: [AuthService, LocalStrategy],
})
export class AuthModule {}

编写 AuthService,添加 login() 方法:

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt/dist';
import { UsersService } from 'src/users/users.service';

@Injectable()
export class AuthService {
    constructor(
        private readonly usersService: UsersService,
        private readonly jwtService: JwtService,
    ) {}

    async validateUser(username: string, pwd: string) {
        const user = await this.usersService.findOne(username);
        if (user && user.password === pwd) {
            const { password, ...result } = user;
            return result;
        }
        return null;
    }

    async login(user: any) {
        const payload = { username: user.username, sub: user.userId };
        return {
            // 使用 jwtService.sign() 基于 payload 生成 token 字符串
            access_token: this.jwtService.sign(payload), 
        };
    }
}

更新 auth.module.ts,对 JwtModule 进行配置,并导出 AuthService: 

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport/dist';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';

@Module({
  imports: [
    UsersModule,
    PassportModule,
    /* 配置 JwtModule */
    JwtModule.register({
      secret: 'ceshi', // 使用 token 签名密文,我在这里是写固定的,实际开发里面,不能这样
      signOptions: { expiresIn: '7d' }, // 设置 token 的有效期,七天
    }),
  ],
  providers: [AuthService, LocalStrategy],
  exports: [AuthService], // 导出 AuthService
})
export class AuthModule {}

有关 Nest JwtModule 的更多信息请参见 GitHub - @nestjs/jwt

有关可用配置选项的更多信息请参见 GitHub - node-jsonwebtoken

更新 /login 路由,返回 JWT:

import { Controller, Req, Post, UseGuards } from '@nestjs/common';
import { Request } from 'express';
import { AuthGuard } from '@nestjs/passport/dist/auth.guard';
import { AuthService } from './auth/auth.service';

@Controller()
export class AppController {
    constructor(private readonly authService: AuthService) {} // 依赖注入

    @UseGuards(AuthGuard('local'))
    @Post('login')
    async getHello(@Req() request: Request) {
        return this.authService.login(request.user); // 调用 login 方法
    }
}

检验 token

在 auth 目录下新增编写本地策略的配置文件 jwt.strategy.ts

import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromHeader('token'),
      ignoreExpiration: false,
      secretOrKey: 'ceshi', // 使用 token 签名密文来解密,我在这里是写固定的,实际开发里面,不能这样
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

3.1代码说明

在 AuthModule 中添加 JwtStrategy 作为提供者:

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport/dist';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';

@Module({
  imports: [
    UsersModule,
    PassportModule,
    JwtModule.register({
      secret: 'ceshi', // 使用 token 签名密文,我在这里是写固定的,实际开发里面,不能这样
      signOptions: { expiresIn: '7d' },
    }),
  ],
  providers: [AuthService, LocalStrategy, JwtStrategy], // 注册 JwtStrategy
  exports: [AuthService],
})
export class AuthModule {}

更新 app.controller.ts 文件,使用 JWT:

import { Controller, Req, Post, UseGuards, Get } from '@nestjs/common';
import { Request } from 'express';
import { AuthGuard } from '@nestjs/passport/dist/auth.guard';
import { AuthService } from './auth/auth.service';

@Controller()
export class AppController {
    constructor(private readonly authService: AuthService) {}

    @UseGuards(AuthGuard('local'))
    @Post('login')
    async getHello(@Req() request: Request) {
        return this.authService.login(request.user);
    }

    @UseGuards(AuthGuard('jwt')) // 使用 JWT 鉴权
    @Get('profile')
    getProfile(@Req() request: Request) {
        return request.user; // 返回用户信息
    }
}

默认策略 

在 AppController 中,使用 @UseGuards(AuthGuard(XXX)) 装饰器需要传递策略的名称 XXX。我们可以声明一个默认策略,就不必再传入名称了。

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport/dist';
import { UsersModule } from 'src/users/users.module';
import { AuthService } from './auth.service';
import { jwtConstants } from './constants';
import { JwtStrategy } from './jwt.strategy';
import { LocalStrategy } from './local.strategy';

@Module({
    imports: [
        UsersModule,
        PassportModule.register({ defaultStrategy: 'jwt' }), // 配置默认策略
        JwtModule.register({
            secret: jwtConstants.secret,
            signOptions: { expiresIn: '60s' },
        }),
    ],
    providers: [AuthService, LocalStrategy, JwtStrategy],
    exports: [AuthService],
})
export class AuthModule {}

示例代码:

可以从这里下载示例代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/245175.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode刷题笔记(4)】【Python】【移动零】【简单】

文章目录 题目描述示例 1示例 2提示 解决方案题意拆解双指针算法双指针法的主要优点双指针法的使用场景举例: 解决方案:【双指针一次遍历】解题心得方案代码运行结果复杂度分析 结束语 移动零 题目描述 给定一个数组 nums,编写一个函数将所…

OWASP ESAPI 预防XSS跨站脚本攻击

跨站脚本攻击XSS案例&#xff1a;跨站脚本攻击XSS案例及其解决方案_xss攻击案例-CSDN博客 Java集成&#xff1a; 1、引入maven <!--OWASP ESAPI&#xff0c;防御 XSS跨站攻击--><dependency><groupId>org.owasp.esapi</groupId><artifactId>esa…

ArrayList集合的两个实例应用,有趣的洗牌算法与杨辉三角

本节课的内容&#xff0c;就让我们来学习一下ArrayList集合的应用&#xff0c;ArrayList的本质就是一个顺序表&#xff0c;那下面一起来学习吧 目录 一、杨辉三角 1.题目详情及链接 2.剖析题目 3.思路及代码 二、洗牌算法 1.创造牌对象 2.创造一副牌 3.洗牌操作 4.发…

Alibaba分布式事务组件Seata AT实战

1. 分布式事务简介 1.1 本地事务 大多数场景下&#xff0c;我们的应用都只需要操作单一的数据库&#xff0c;这种情况下的事务称之为本地事务(Local Transaction)。本地事务的ACID特性是数据库直接提供支持。本地事务应用架构如下所示&#xff1a; 在JDBC编程中&#xff0c;我…

力扣24 两两交换链表中的节点 Java版本

文章目录 题目解题方法Code 题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;hea…

事务隔离级别:保障数据库并发事务的一致性与性能

目录 引言 1. 事务隔离级别概述 2. 读未提交隔离级别 3. 读已提交隔离级别 4. 可重复读隔离级别 5. 串行化隔离级别 6. 保障事务隔离级别的机制 7. 如何选择合适的隔离级别 8. 结语 引言 在数据库管理系统&#xff08;DBMS&#xff09;中&#xff0c;事务隔离级别是一…

12.14_黑马数据结构与算法笔记Java

目录 120 二叉搜索树 min max 121 二叉搜索树 put 122 二叉搜索树 前任后任1 123 二叉搜索树 前任后任2 124 二叉搜索树 删除1 125 二叉搜索树 删除2 126 二叉搜索树 删除3 127 二叉搜索树 删除 递归1 128 二叉搜索树 删除 递归2 129 二叉搜索树 范围查询 130 二叉搜…

ADC学习总结

ADC的架构分类&#xff1a; 1、Delta-Sigma 采样率一般是在1M以内&#xff0c;位数一般可以做的很高&#xff0c;比如24位&#xff0c;Delta-Sigma ADC采用了过采样技术&#xff0c;不需要在模拟输入端加抗混叠滤波&#xff0c;由后端数字滤波器进行处理&#xff0c;通过信噪…

网工内推 | IT经理,50k*14薪,NP以上即可,七险一金

01 海天瑞声 招聘岗位&#xff1a;IT经理 职责描述&#xff1a; 1、IT基础架构的方案制定、实施和日常维护&#xff0c;包括机房建设运维、服务器配置及运维、网络规划及运维、上网行为管理、电话、电话、监控、门禁等各类弱电系统搭建及运维 2、负责公司环境及网络安全防御体…

WEB服务器介绍

Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器连到服务器上并请求文件时&#xff0c;服务器将处理该请求并将文件发送到该浏览器上&#xff0c;附带的信息会告诉浏览器如何查看该文件&#xff0c;即文WEB服务器件类型。服务器使用HTTP进行信息交流&#xff0c…

ASF-YOLO开源 | SSFF融合+TPE编码+CPAM注意力,精度提升!

目录 摘要 1 Introduction 2 Related work 2.1 Cell instance segmentation 2.2 Improved YOLO for instance segmentation 3 The proposed ASF-YOLO model 3.1 Overall architecture 3.2 Scale sequence feature fusion module 3.3 Triple feature encoding module …

Kvaser Leaf v3 重磅上新!报文速率高达20000条/秒!支持CAN FD!EAN: 73-30130-01424-4

作为CAN总线领域的专家&#xff0c;Kvaser深耕行业40年&#xff0c;至今已经累计推出100多款CAN产品。其中稳定小巧、便携易用的Kvaser经典Leaf系列是将计算机与CAN网络连接并获取CAN/CAN FD数据的最简单、性价比最高的方法之一。Kvaser秉持着将用户放在重要位置的原则&#xf…

6.5.编解码器信息的收集

那在上节课中呢&#xff1f;我向你介绍了add track相关的内容&#xff0c;那今天呢&#xff1f;我们来看看编解码器信息的收集。那在这里呢&#xff0c;我们需要问几个重要的问题&#xff0c;那首先呢&#xff0c;就是我们上节课通过&#xff0c;可以让web rtc知道我们都要传输…

智能优化算法应用:基于旗鱼算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于旗鱼算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于旗鱼算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.旗鱼算法4.实验参数设定5.算法结果6.参考文献7.MA…

优先考虑静态成员类

在Java中&#xff0c;静态成员类&#xff08;static nested class&#xff09;是一种嵌套在另一个类中的类&#xff0c;且被声明为静态。静态成员类不依赖于外部类的实例&#xff0c;可以直接通过外部类的类名来访问。 优先考虑使用静态成员类的情况通常是当这个类与外部类的实…

一文带你了解UI自动化测试框架

PythonSeleniumUnittestDdtHTMLReport分布式数据驱动自动化测试框架结构 1、Business&#xff1a;公共业务模块&#xff0c;如登录模块&#xff0c;可以把登录模块进行封装供调用 ------login_business.py from Page_Object.Common_Page.login_page import Login_Page from H…

探秘闭包:隐藏在函数背后的小秘密(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

C# 图解教程 第5版 —— 第17章 转换

文章目录 17.1 什么是转换17.2 隐式转换17.3 显示转换和强制转换17.4 转换的类型17.5 数字的转换17.5.1 隐式数字转换17.5.2 溢出检测上下文17.5.3 显示数字转换 17.6 引用转换17.6.1 隐式引用转换17.6.2 显式引用转换17.6.3 有效显式引用转换 17.7 装箱转换17.7.1 装箱是创建副…

小程序 -网络请求post/get

1.1网络请求的概念(post和get) 1.2步骤 1.3 应用函数 js里面写&#xff0c;用bindtap绑在控件上&#xff0c;就不讲了 实例代码&#xff1a; //发起get数据请求get_info(){wx.request({url:https://www.escook.cn/api/get,//请求的接口地址,必须基于https协议//请求的方式met…

SpringBoot的Starter自动化配置,自己编写配置maven依赖且使用及短信发送案例

目录 一、Starter机制 1. 是什么 2. 有什么用 3. 应用场景 二、短信发送案例 1. 创建 2. 配置 3. 编写 4. 形成依赖 6. 其他项目的使用 每篇一获 一、Starter机制 1. 是什么 SpringBoot中的starter是一种非常重要的机制(自动化配置)&#xff0c;能够抛弃以前繁杂…