如何创建isAdmin权限验证中间件?Express框架实现方案
Express Admin权限中间件实现方案(解决TypeScript报错)
问题背景
已实现基于JWT的身份验证中间件authMiddleware,现在需要新增一个中间件,在身份验证通过后检查用户的isAdmin字段是否为true。自行编写时出现TypeScript错误:
Property 'isAdmin' does not exist on type 'string'.ts(2339)
错误原因
- 原
authMiddleware仅将用户ID(字符串类型)挂载到req.userId,isAdmin是用户实体的字段,并非string类型的属性,直接访问req.userId.isAdmin必然报错。 - 错误地嵌套调用
authMiddleware,不符合Express中间件的链式调用逻辑。 - 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
相关产品推荐
相关产品推荐

