请求上下文

简介: 请求上下文

需求

随着系统的复杂性增加,我们很容易遇到一种场景,就是想要知道当前进行资源操作的究竟是谁。比如,系统中有超过一个用户拥有删除商品的权限,某一天突然发现有个商品被删除了(我们系统全部是软删除,这里以软删除举例),想要知道删除这个商品的究竟是谁。再比如,系统中有超过一个用户拥有发送系统通知的权限,追溯某一条通知是谁发的也是一样的道理。


上面这些案例如果系统日志和用户活动日志做的足够好的话,是可以达到目的的。但是有一些场景,系统日志和用户活动日志就无能为力了,比如本文所介绍的 RBAC 扩展场景。


方案调研

由于此部分篇幅过长,抽离到独立笔记:方案调研


方案实现

不要跳过上一步直接看这个!根据需求来看是否需要这种方案!


Step1. 安装依赖

$ yarn add cls-hooked
$ yarn add -D @types/cls-hooked点击复制复制失败已复制


Step2. 构造请求上下文类—— RequestContext

request.context.ts 文件中写入如下内容:

import { getNamespace } from 'cls-hooked';
import { Request, Response } from 'express';
import { v4 as uuid } from 'uuid';
import { JwtPayload } from '../../user/interfaces/jwt-payload.interface';
export class RequestContext {
  public static nsid = uuid();
  public uuid: string;
  public request: Request;
  public response: Response;
  /**
   * 请求上下文构造函数
   * @param request 请求对象
   * @param response 返回对象
   */
  constructor(request: Request, response: Response) {
    this.uuid = uuid();
    this.request = request;
    this.response = response;
  }
  /**
   * 获取请求上下文
   * @returns 当前请求上下文
   */
  public static currentRequestContext(): RequestContext {
    const namespace = getNamespace(RequestContext.nsid);
    return namespace && namespace.active ? namespace.get(RequestContext.name) : null;
  }
  /**
   * 获取当前请求
   * @returns 当前请求
   */
  public static currentRequest(): Request {
    const requestContext = RequestContext.currentRequestContext();
    return requestContext?.request;
  }
  /**
   * 获取当前用户
   * @returns 当前用户
   */
  public static currentUser(): JwtPayload {
    const requestContext = RequestContext.currentRequestContext();
    return requestContext?.request?.user;
  }
}点击复制复制失败已复制


提示

项目采用 jwt 的方式进行校验,将用户信息解密后挂载到 Request 请求中,所以在 types.d.ts 中扩展了 express 中的 Request 对象。当前操作用户可以通过 express.Request.user 来拿到。


Step3. 编写中间件—— RequestContextMiddleware

request-context.middleware.ts 文件中写入如下内容:

import { NextFunction, Response, Request } from 'express';
import { RequestContext } from '../context/request.context';
import { getNamespace, createNamespace } from 'cls-hooked';
/**
 * 请求上下文中间件
 * @param req 请求参数
 * @param res 返回参数
 * @param next next函数
 */
export function RequestContextMiddleware(req: Request, res: Response, next: NextFunction) {
  const requestContext = new RequestContext(req, res);
  const namespace = getNamespace(RequestContext.nsid) || createNamespace(RequestContext.nsid);
  namespace.run(() => {
    namespace.set(RequestContext.name, requestContext);
    next();
  });
}点击复制复制失败已复制


Step4. 启用中间件

最简单的是全局启用中间件,在 app.module.ts 中进行如下配置:

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(RequestContextMiddleware).forRoutes({ path: '*', method: RequestMethod.ALL });
  }
}点击复制复制失败已复制


提示

启用这个中间件会损耗性能,全局启用并不合适,应该在需要的地方单独配置!比如,我们的场景在查询时不需要上下文功能,完全没有必要用 RequestMethod.ALL ,具体如何配置请结合自己的实际场景进行思考。

目录
相关文章
|
前端开发
前端通过input标签封装Upload组件实现文件上传
前端通过input标签封装Upload组件实现文件上传
420 0
|
NoSQL Ubuntu Redis
【Docker 系列】docker 学习 二,Docker 的常用命令
【Docker 系列】docker 学习 二,Docker 的常用命令
199 0
|
安全 Linux C++
Linux线程的加锁
Linux线程的加锁
135 0
Linux线程的加锁
|
NoSQL 数据库 索引
海量结构化数据存储技术揭秘:Tablestore表设计最佳实践
前言 表格存储Tablestore是阿里云自研的面向海量结构化数据存储的Serverless NoSQL多模型数据库。在处理海量数据时,方案设计非常重要,合理的设计才能够发挥出数据库的性能水平。本文主要介绍Tablestore在表设计方面的一些实践经验,供大家参考。
10678 1
26、【支付模块开发】——支付宝回调函数实现和查询用户订单状态接口编写
1、支付宝回调函数实现 我们在调试支付宝沙箱环境的时候,支护宝会有一个回调函数,也就是在支付成功之后,可以调用我们支付之后需要执行的相关方法,从而达到数据库的数据和我们的操作相统一。
3404 0
|
8天前
|
人工智能 运维 安全
|
5天前
|
人工智能 异构计算
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
|
7天前
|
机器学习/深度学习 人工智能 自然语言处理
B站开源IndexTTS2,用极致表现力颠覆听觉体验
在语音合成技术不断演进的背景下,早期版本的IndexTTS虽然在多场景应用中展现出良好的表现,但在情感表达的细腻度与时长控制的精准性方面仍存在提升空间。为了解决这些问题,并进一步推动零样本语音合成在实际场景中的落地能力,B站语音团队对模型架构与训练策略进行了深度优化,推出了全新一代语音合成模型——IndexTTS2 。
627 22
|
6天前
|
人工智能 测试技术 API
智能体(AI Agent)搭建全攻略:从概念到实践的终极指南
在人工智能浪潮中,智能体(AI Agent)正成为变革性技术。它们具备自主决策、环境感知、任务执行等能力,广泛应用于日常任务与商业流程。本文详解智能体概念、架构及七步搭建指南,助你打造专属智能体,迎接智能自动化新时代。