Azure Function App JWT认证问题:报错与未授权CRUD操作
解决方案
问题根源分析
- Promise与
context.done()混用错误:入口函数是async函数(返回Promise),但认证失败时调用了context.done(),Azure Functions不允许同时使用这两种方式结束函数执行,因此抛出该错误。 - CRUD操作未被拦截:认证失败时虽设置了401响应,但未终止入口函数的后续执行流程,导致
switch里的CRUD逻辑仍会运行。
修改方案
1. 重构JWT认证中间件
移除context.done(),改为通过抛出异常终止流程,同时设置好401响应:
module.exports = { authenticate: async (context, req) => { const token = extractToken(req); try { // 验证令牌 const decoded = jwt.verify(token, process.env.JWT_TOKEN_KEY); if (decoded) { let query = 'XXX'; const data = await PortalDB.query(query, { type: QueryTypes.SELECT }); context.auth = data; return; // 认证成功,直接返回 } } catch (error) { const [status, message] = !token ? [401, 'Unauthorized: Token missing'] : [401, `Unauthorized: Invalid token: ${error.message}`]; // 设置401响应 context.res = { status, body: message }; // 抛出异常,触发入口函数的catch逻辑,终止后续流程 throw new Error(message); } }, }; function extractToken(req) { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return null; } return authHeader.substring(7); }
2. 调整入口函数的错误处理
在入口函数的catch块中区分认证错误与其他错误,确保认证失败时直接返回已设置的401响应,不执行CRUD操作:
module.exports = async (context, req) => { try { await connectToMongoDB(); await jwtAuthMiddleware.authenticate(context, req); // 认证失败会抛出异常 // 只有认证成功才会执行以下CRUD逻辑 switch (req.method) { case 'POST' : if (req.body && !req.body._id) { await createContainer(context, req.body); } else if (req.body && req.body._id) { await editContainer(context, req.body); } else { context.res = { status: 400, body: { 'success': false, 'message': 'An error has occurred' } }; } break; case 'GET' : await getContainers(context, req.query.id); break; case 'DELETE' : await deleteContainer(context, req.query.id); break; default : context.res = { status: 405, body: 'Method not allowed for this endpoint.', }; break; } } catch (error) { // 如果是认证错误,中间件已经设置好响应,直接返回 if (error.message.startsWith('Unauthorized')) { return; } // 其他业务错误返回400 context.res = { status: 400, body: { 'success': false, 'message': 'An error has occurred' } }; } }
关键改进点
- 移除
context.done(),统一使用async/await+异常抛出的方式管理函数生命周期,解决混用错误。 - 认证失败时通过抛出异常,直接触发入口函数的
catch逻辑,终止后续CRUD代码执行,避免未授权的数据库操作。 - 无需额外检查
context.auth,认证失败的流程被完全拦截,从根源杜绝安全漏洞。
内容的提问来源于stack exchange,提问作者Jordan
相关产品推荐
相关产品推荐

