You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建isAdmin权限验证中间件?Express框架实现方案

Express Admin权限中间件实现方案(解决TypeScript报错)

问题背景

已实现基于JWT的身份验证中间件authMiddleware,现在需要新增一个中间件,在身份验证通过后检查用户的isAdmin字段是否为true。自行编写时出现TypeScript错误:

Property 'isAdmin' does not exist on type 'string'.ts(2339)

错误原因

  1. 原authMiddleware仅将用户ID(字符串类型)挂载到req.userId,isAdmin是用户实体的字段,并非string类型的属性,直接访问req.userId.isAdmin必然报错。
  2. 错误地嵌套调用authMiddleware,不符合Express中间件的链式调用逻辑。
  3. TypeScript未识别自定义的请求属性,导致类型校验不通过。

解决方案

方案一:将isAdmin存入JWT Payload(无需额外查库)

适合不需要实时同步isAdmin状态的场景,生成JWT时将isAdmin写入Payload,验证时直接提取使用。

1. 修改TokenPayload接口

更新authMiddleware中的TokenPayload,加入isAdmin字段:

interface TokenPayload {
  id: string;
  isAdmin: boolean;
  iat: number;
  exp: number;
}

2. 扩展Express Request类型

创建src/types/express.d.ts文件,让TypeScript识别自定义请求属性:

declare namespace Express {
  export interface Request {
    userId: string;
    isAdmin: boolean;
  }
}

注意:确保tsconfig.json中包含此类型文件的扫描路径。

3. 更新authMiddleware

验证JWT后,将isAdmin挂载到请求对象:

import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

interface TokenPayload {
  id: string;
  isAdmin: boolean;
  iat: number;
  exp: number;
}

export default async function authMiddleware(
  req: Request, res: Response, next: NextFunction
) {
  const { authorization } = req.headers;

  if (!authorization) {
    return res.status(401).json('无效的授权信息');
  }

  const token = authorization.replace('Bearer ', '').trim();

  try {
    const secret = process.env.JWT_SECRET as string;
    const data = jwt.verify(token, secret);

    const { id, isAdmin } = data as TokenPayload;

    req.userId = id;
    req.isAdmin = isAdmin;

    return next();
  } catch (err) {
    return res.status(401).json('令牌验证失败');
  }
}

4. 编写Admin中间件

无需嵌套调用authMiddleware,直接作为链式中间件使用:

import { Request, Response, NextFunction } from 'express';

export default async function authAdminMiddleware(
  req: Request, res: Response, next: NextFunction
) {
  if (req.isAdmin) {
    return next();
  }
  return res.status(403).json('你无权执行此操作!');
}

5. 路由使用

router.post('/', authMiddleware, authAdminMiddleware, CreatePost.store);

方案二:从数据库查询用户权限(实时同步状态)

适合需要实时获取isAdmin最新状态的场景,通过用户ID从数据库查询用户实体。

1. 扩展Express Request类型

创建src/types/express.d.ts:

declare namespace Express {
  export interface Request {
    userId: string;
  }
}

2. 编写Admin中间件

引入用户模型,根据req.userId查询用户并检查权限:

import { Request, Response, NextFunction } from 'express';
import User from '../models/User'; // 替换为你的用户模型路径

export default async function authAdminMiddleware(
  req: Request, res: Response, next: NextFunction
) {
  try {
    const user = await User.findById(req.userId);
    
    if (!user) {
      return res.status(404).json('用户不存在');
    }

    if (user.isAdmin) {
      return next();
    }

    return res.status(403).json('你无权执行此操作!');
  } catch (err) {
    return res.status(500).json('服务器内部错误');
  }
}

3. 路由使用

router.post('/', authMiddleware, authAdminMiddleware, CreatePost.store);

关键注意事项

  • 避免嵌套调用中间件,Express中间件本身是链式执行的,直接按顺序挂载即可。
  • 必须扩展Express的Request类型,否则TypeScript会对自定义属性报错。
  • 方案一中生成JWT时,要确保将isAdmin字段写入Payload(比如注册/登录时签发令牌的逻辑)。

内容的提问来源于stack exchange,提问作者Routfin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 14:35:11