基于Nest.js+Mongodb+定时任务实现发送邮件功能(进行接口签名、鉴权)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

基于Nest.js+Mongodb+定时任务实现发送邮件功能(进行接口鉴权)
现实开发中,我们可能会遇到参数被篡改的情况,所以一般一些重要的接口都会进行签名校验,实现过程是前端和后端进行统一的签名方式和秘钥去生成签名,后端对比签名是否一致,不一致则直接拒绝访问,不再进行操作。


一、签名是什么?

为什么需要 API 接口签名

1.保证请求数据正确
当请求中的某一个字段的值变化时,原有的签名结果就会发生变化。所以,只要参数发生变化,签名就要发生变化,否则请求将会是一个无效的请求。

2.保证请求来源合法
一般情况下,生成签名的算法都会成对出现一个 appKey 和一个 appSecret,根据 appKey 能识别出调用者身份;根据 appSecret 能识别出签名是否合法。

3.识别接口的时效性(设计个过期时间 )
一般情况下,签名和参数中会包含时间戳,这样服务端就可以验证客户端请求是否在有效时间内,从而避免被人恶意刷接口。

二、步骤

1.引入中间件

提示:当然使用别的也可以。nestjs中提供(中间件、过滤器、守卫、管道、拦截器)供我们使用
代码如下(示例):首先说一下我的思路,就是前端通过与后端相同的加密思路加密签名
将他们作为信息传入后端接口,通过中间件处理 签名有效放行,签名无效401

代码实现

import {
  Injectable,
  NestMiddleware,
  Param,
  Get,
  Query,
  Req,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import * as crypto from 'crypto';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class EmailMiddleware implements NestMiddleware {
  constructor(private configService: ConfigService) {}

  private secret = '123456'; //密钥 不能硬编码
  use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');

	//通过获取外部配置文件的方式解决硬编码问题
    const appkey = this.configService.get<string>('database.appkey');

    const dbHost = this.configService.get<string>('database.host', 'localhost');

    const zhengxifeng = this.configService.get<string>('ZXF');

    console.log(zhengxifeng + 'zhengxifeng');

    console.log(appkey + '从.env文件中获取的');
    console.log(dbHost + '从.env文件中获取的');
    const signature = req.headers['x-singsture']; //获取签名值
    const timestamp = req.headers['x-timestamp'] as string; //时间戳
    const nonce = req.headers['x-nonce']; //请求头获取随机数
    const params = req.query; //获取url后面?的信息  (查询参数)
    const params1 = req.body; //获取请求体信息  (post请求)

    console.log('时间戳');
    console.log(timestamp);
    console.log('当前时间');
    console.log(Date.now());
    console.log('随机数');
    console.log(nonce);
    console.log('post中的信息');
    console.log(params1);
    console.log('******************************');
    console.log(signature);
    console.log('******************************');

    const dateInt = parseInt(timestamp);
    console.log('前端时间戳信息' + dateInt);

    if (Date.now() - dateInt > 1200000000) {//我是用的简单的判断  
      //200分钟有效
      console.log('datade 信息' + Date.now());
      throw new HttpException('请求已过期', HttpStatus.UNAUTHORIZED);
    }

    //
    // const tt = //秒
    const paramList = Object.keys(params1)
      .sort()
      .map((key) => `${key}=${params1[key]}`);

    console.log('将请求携带的参数转换List');
    console.log(paramList);

    const paramString = paramList.join('&');

    console.log('拼接');
    console.log(paramString);

    const message = `${timestamp}${nonce}${paramString}`;

    console.log('将时间戳随机数请求信息转换成大的字符串');
    console.log(message);

    // 使用密钥对待签名的字符串进行HMAC-SHA256签名
    const hmac = crypto.createHmac('sha256', appkey);
    const signatureComputed = hmac.update(message).digest('hex');

    console.log('计算得到的签名');
    console.log(signatureComputed);

    // 验证签名是否正确
    if (signature === signatureComputed) {
      next(); // 签名验证通过,继续处理请求
    } else {
      res.status(401).send('Unauthorized'); // 签名验证失败,返回401错误
    }
  }
}

postman调用

前端携带的数据
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值