MERN Stack中JWT Admin权限验证返回403 Forbidden问题
问题:MERN Stack中JWT Admin授权返回403 Forbidden
我正在基于MERN Stack优化网站,已实现JWT授权验证。使用数据库中标记为admin的账号通过Postman发送请求时,收到了我在中间件中定义的403 Forbidden提示(用于拦截非admin用户操作)。我仅将该中间件添加到/users路由做测试,但JWT并未正常生效,问题依旧存在。
相关代码
middleware.js
import jwt from 'jsonwebtoken'; export const authMiddleware = (req, res, next) => { const token = req.headers['authorization']?.split(' ')[1]; // 从Authorization头获取token if (!token) { return res.status(401).json({ message: 'Unauthorized' }); } jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, decodedToken) => { if (err) { console.log(err); return res.status(400).json({ message: 'Invalid token' }); } if (decodedToken.usertype === 'ADMIN') { // 若为admin则继续执行 next(); } else { // 无admin权限则拦截 return res.status(403).json({ message: 'Forbidden' }); } }); };
adminRouter.js
import express from 'express'; import mongoose from 'mongoose'; import AdminModel from '../models/adminModel.js'; import bcrypt from 'bcryptjs'; import CourseModel from '../models/courseModel.js'; import UserModel from '../models/userModel.js'; import ActivityModel from '../models/activityModel.js'; import jwt from 'jsonwebtoken'; import dotenv from 'dotenv'; import { authMiddleware } from '../middlewares/middleware.js'; const router = express.Router(); dotenv.config(); router.post('/signup', async (req, res) => { try { const { fullName, password, phoneNumber, email } = req.body; const adminExist = await AdminModel.findOne({ email }) if (adminExist) return res.status(400).json({ message: 'admin already exist' }) const hashedPassword = await bcrypt.hash(password, 15) const createdUser = await AdminModel.create({ fullName, email, password: hashedPassword, phoneNumber, usertype: "ADMIN" }) return res.status(201).json(createdUser); } catch (error) { console.log(error) return res.json({ message: 'admin oluşturulamadı' }) } }); router.post('/signin', async (req, res) => { try { const { email, password } = req.body; const admin = await AdminModel.findOne({ email }); if (!admin) { return res.status(400).json({ message: "admin yok" }); } const isPasswordCorrect = await bcrypt.compare(password, admin.password); if (!isPasswordCorrect) { return res.status(400).json({ message: "wrong password" }); } const accessToken = jwt.sign( { adminId: admin._id }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: '15m' } ); const refreshToken = jwt.sign( { email: admin.email, password: admin.password }, process.env.REFRESH_TOKEN_SECRET ); return res.status(200).json({ admin, accessToken, refreshToken, message: "kimlik doğrulama başarılı" }); } catch (error) { return res.status(400).json({ message: error.message }); } }); // 以下省略其他路由代码... router.get('/users', authMiddleware, async (req, res) => { try { const users = await UserModel.find(); return res.status(200).json(users); } catch (error) { return res.status(500).json({ message: error.message }); } }); // 其他路由代码... export default router;
解决方案
核心问题
生成accessToken时未将usertype字段存入JWT payload,导致中间件解析token时无法获取decodedToken.usertype,因此判定为非admin用户返回403。
修复步骤
- 修改signin接口的accessToken生成逻辑,加入
usertype字段:
const accessToken = jwt.sign( { adminId: admin._id, usertype: admin.usertype }, // 添加usertype到payload process.env.ACCESS_TOKEN_SECRET, { expiresIn: '15m' } );
- 可选调试优化:在中间件中打印解析后的token,确认字段是否存在:
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, decodedToken) => { if (err) { console.log(err); return res.status(400).json({ message: 'Invalid token' }); } console.log('解析后的Token:', decodedToken); // 调试用日志 if (decodedToken.usertype === 'ADMIN') { next(); } else { return res.status(403).json({ message: 'Forbidden' }); } });
- 安全优化:refreshToken中不要存入password哈希值,仅保留必要信息:
const refreshToken = jwt.sign( { email: admin.email, usertype: admin.usertype }, // 移除password字段 process.env.REFRESH_TOKEN_SECRET );
内容的提问来源于stack exchange,提问作者Meliqe
相关产品推荐
相关产品推荐

