为了保护REST API,我正在使用中间件来检查用户的JWT令牌,并仅允许该特定用户访问自己的数据。
在auth.js中
const jwt = require('jsonwebtoken')
const User = require('../models/user')
const auth = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '')
const decoded = jwt.verify(token, process.env.JWT_SECRET)
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token })
if (!user) { // If no user is found
throw new Error()
}
// if there's a user
req.token = token
req.user = user
next()
} catch (e) {
res.status(401).send({ error: 'Please authenticate.' })
}
}
module.exports = auth
在其中一个获取/更新路由器中
router.get('/itemShipmentStatus', auth, async (req, res) => {
// Get the items shipment status from db.
})
但是,我注意到我需要创建一个新的admin用户(例如admin 1,admin2)来获取和更新所有用户的itemShipmentStatus。有没有一种方法可以通过中间件(auth.js?)实现用户组身份验证
更新:
我能想到的唯一解决方案是在创建新用户时向用户文档添加另一个“ userGroup”字段。然后在中间件auth.js中添加另一个条件,以检查用户是否属于管理组。
if (!user || user.userGroup !== 'Admin') { // If no user is found
throw new Error()
}
这是常规的做法吗?
答案 0 :(得分:2)
我建议添加存储在用户中的permissions
数组。这样,您将更加灵活。然后
const auth = (allowedPermission) => (async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '')
const decoded = jwt.verify(token, process.env.JWT_SECRET)
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token })
if (!user) { // If no user is found
throw new Error()
}
if (!user.permissions.includes(allowedPermission)){
throw new Error() // Forbidden 403
}
// if there's a user
req.token = token
req.user = user
next()
} catch (e) {
res.status(401).send({ error: 'Please authenticate.' })
}
})
和在路线
router.get('/itemShipmentStatus', auth([admin, user]), async (req, res) => {
// Get the items shipment status from db.
})
然后要确定要运行的正确代码。
我建议考虑api的划分。公用api和管理api。这是因为从概念上讲,用户可能希望成为管理员并访问其自己的itemShipmentStatus。因此拥有
router.get('/itemShipmentStatus', auth([admin, user]), async (req, res) => {
// Get the items shipment status from db.
})
router.get('/admin/itemShipmentStatus', auth([admin]), async (req, res) => {
// Get the items shipment status from db of all user.
})
这允许管理员用户以普通用户身份测试API并以管理员身份获得所有状态。
答案 1 :(得分:0)
更传统的方法是创建一个AuthRouter
,它扩展了默认的express.Router
并检查允许的角色,因此无需为每个路由使用中间件。
扩展express.Router
来检查角色:
const express = require('express');
const jwt = require('jsonwebtoken');
const User = require('../models/user');
export default class AuthRouter extends express.Router {
addRoles(...roles) {
return this.use(checkAccessForRoles(...roles));
}
}
const checkAccessForRoles = (...roles) => async (req, res, next) => {
const token = req.header('Authorization').replace('Bearer ', '');
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token });
if (!roles.includes(user.role)) throw new Error('Forbidden');
req.user = user;
return next();
};
为AuthRouter
用户角色使用ADMIN
:
const adminRouter = new AuthRouter({
prefix: '/admin',
})
.addRoles(['ADMIN']);
adminRouter.get('/itemShipmentStatus', async (req, res) => {
// Get the items shipment status from db.
});