这里是我的授权中间件,我在一个路径中这样使用它:
router.get('/dashboard', authorize(), dashboard);
因此,正如您所看到的,只有授权用户才能访问仪表板,对吗?
以下是功能:
const jwt = require('express-jwt');
module.exports = authorize;
function authorize(roles = []) {
// roles param can be a single role string (e.g. Role.User or 'User')
// or an array of roles (e.g. [Role.Admin, Role.User] or ['Admin', 'User'])
if (typeof roles === 'string') {
roles = [roles];
}
return [
// authenticate JWT token and attach user to request object (req.user)
jwt({ secret, algorithms: ['HS256'] }),
// authorize based on user role
async (req, res, next) => {
const account = await db.Account.findById(req.user.id);
const refreshTokens = await db.RefreshToken.find({ account: account.id });
if (!account || (roles.length && !roles.includes(account.role))) {
// account no longer exists or role not authorized
return res.status(401).json({ message: 'Unauthorized' });
}
// authentication and authorization successful
req.user.role = account.role;
req.user.ownsToken = token => !!refreshTokens.find(x => x.token === token);
next();
}
];
}
--这是对函数到底要做什么的解释,(现在可以跳过它):
可以将授权中间件添加到任何路由,以将对路由的访问限制为具有指定角色的经过身份验证的用户。如果省略了roles参数(也就是授权()),那么不管角色如何,所有经过身份验证的用户都可以访问该路由。帐户控制器使用它来限制对帐户CRUD路由的访问和撤销令牌路由。
授权函数返回一个包含两个中间件函数的数组:
第一个(jwt({ ... }))
通过验证请求的“授权”头中的JWT访问令牌来验证请求。在成功的身份验证中,用户对象被附加到包含来自JWT令牌的数据的req
对象,在本例中该数据包含用户id (req.user.id)
。
第二种方法是通过检查经过身份验证的帐户是否仍然存在并根据其角色授权访问所请求的路由来授权请求。第二个中间件函数还将角色属性和ownsToken
方法附加到req.user
对象,以便控制器函数能够访问它们。如果身份验证或授权失败,则返回401未经授权的响应。
,这就是我想做的:
当这个中间件被触发时,我想将jwtToken添加到授权头中,好吗?
因此,我将其添加到函数的开头:
function authorize(roles = []) {
// roles param can be a single role string (e.g. Role.User or 'User')
// or an array of roles (e.g. [Role.Admin, Role.User] or ['Admin', 'User'])
if (typeof roles === 'string') {
roles = [roles];
}
// This is the code I added
const jwtToken = req.cookies.jwtToken; // get the jwtToken from cookie
const token = `Bearer ${jwtToken}`; // format the token
res.header('Authorization', 'Bearer '+ token); // simply add the jwtToken to headers
return [
// authenticate JWT token and attach user to request object (req.user)
jwt({ secret, algorithms: ['HS256'] }),
...
无论我如何努力,我都无法做到这一点,因为,我无法访问中间件中的req和res!
如何在req
中间件中访问res
和authorize
?
发布于 2021-08-02 09:29:53
如何用您的方法解决这一问题
authorize
函数是而不是中间件。
它是一个函数,当您调用它时,返回两个中间件函数(在一个数组中)。
第一个中间件函数是:
//验证JWT令牌并将用户附加到请求对象(req.user) jwt({保密,算法:'HS256‘}),
它在user
对象上创建req
属性。
第二个中间件功能是:
//基于用户角色异步的授权(req,res,next) => { //等
要获得对req
对象的访问,请在该函数中执行。
但是,您似乎希望在运行所返回的中间件之前访问它。
要做到这一点,您需要在数组的前端中添加一个第三层中间件函数。
return [
(req, res, next) => {
// access cookies and transfer to header variable here
next();
},
// authenticate JWT token and attach user to request object (req.user)
jwt({ secret, algorithms: ['HS256'] }),
正确的方法
自定义令牌位置 可以使用getToken选项指定用于从请求中提取令牌的自定义函数。如果您需要通过查询参数或cookie传递令牌,这是非常有用的。您可以在这个函数中抛出一个错误,它将由express-jwt处理。 app.use(jwt({秘:'hello !',credentialsRequired: false,getToken:函数fromHeaderOrQuerystring (req) { if (req.headers.authorization & req.headers.authorization.split(‘) === 'Bearer') { else req.headers.authorization.split(’)1;}else if (req.query && req.query.token) {返回req.query.token;}返回null} }));
因此,您可以传递一个getToken
函数,它直接读取cookie,而不是试图重写请求。
发布于 2021-08-02 09:19:43
问题是您要返回一个数组:
return [
jwt({ secret, algorithms: ['HS256'] }),
// authorize based on user role
async (req, res, next) => { /* ... */ }
]
而且Express不知道该怎么处理它。Express期望一个作为中间件的函数(您的async (req,res,next) => ...
)。
解决这一问题的一种方法是使用spread操作符将jwt
中间件和中间件分别传递给Express:
router.get('/dashboard', ...authorize(), dashboard);
这是可行的,但对于其他习惯于Express的开发人员来说,这是不太可能的。看起来有点奇怪。
现在,奇怪的代码没有什么问题,但我认为有一个更好的方法--使用路由器链接您的中间件:
const jwtMiddleware = jwt({ secret, algorithms: ['HS256'] });
function authorize(roles = []) {
// roles param can be a single role string (e.g. Role.User or 'User')
// or an array of roles (e.g. [Role.Admin, Role.User] or ['Admin', 'User'])
if (typeof roles === 'string') {
roles = [roles];
}
let midRouter = express.Router();
midRouter.use(jwtMiddleware);
midRouter.use(async (req, res, next) => {
const account = await db.Account.findById(req.user.id);
const refreshTokens = await db.RefreshToken.find({ account: account.id });
if (!account || (roles.length && !roles.includes(account.role))) {
// account no longer exists or role not authorized
return res.status(401).json({ message: 'Unauthorized' });
}
// authentication and authorization successful
req.user.role = account.role;
req.user.ownsToken = token => !!refreshTokens.find(x => x.token === token);
// authorize based on user role
next();
});
return midRouter;
}
现在您可以使用原始代码:
router.get('/dashboard', authorize(), dashboard);
就我个人而言,我不会去理会这个问题,我只会按照文档中使用express-jwt
的方式使用它:
router.use(jwt({ secret, algorithms: ['HS256']}));
router.get('/dashboard', authorize(), dashboard);
这正是大多数Express开发人员希望看到的,您可以将jwt
部分从authorize()
函数中删除。
请记住,您可以定义一个不希望jwt
身份验证在其.unless()
方法中发生的路径列表。
发布于 2021-08-02 09:37:51
authorize
不是中间件。它执行中间件,所以您所需要做的就是将代码从authorize
向下移到(req, res, next) => {}
函数并返回它。
https://stackoverflow.com/questions/68624387
复制