You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Function App JWT认证问题:报错与未授权CRUD操作

解决方案

问题根源分析

  1. Promise与context.done()混用错误:入口函数是async函数(返回Promise),但认证失败时调用了context.done(),Azure Functions不允许同时使用这两种方式结束函数执行,因此抛出该错误。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 13:45:21