代码之家  ›  专栏  ›  技术社区  ›  Zat42

条带错误:未找到与负载的预期签名匹配的签名

  •  1
  • Zat42  · 技术社区  · 7 年前

    我有一个调用Firebase函数的条带webhook。在这个函数中,我需要验证这个请求是否来自条带服务器。代码如下:

    const functions = require('firebase-functions');
    const bodyParser = require('body-parser');
    const stripe = require("stripe")("sk_test_****");
    const endpointSecret = 'whsec_****';
    const app = require('express')();
    
    app.use(bodyParser.json({
        verify: function (req, res, buf) {
            var url = req.originalUrl;
            if (url.startsWith('/webhook')) {
                req.rawBody = buf.toString()
            }
        }
    }));
    
    app.post('/webhook/example', (req, res) => {
        let sig = req.headers["stripe-signature"];
    
        try {
            console.log(req.bodyRaw)
            let event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
            console.log(event);
            res.status(200).end()
    
            // Do something with event
        }
        catch (err) {
            console.log(err);
            res.status(400).end()
        }
    });
    
    exports.app = functions.https.onRequest(app);
    

    如中所述 Stripe Documentation ,我必须使用原始主体来执行此安全检查。

    app.use(require('body-parser').raw({type: '*/*'}));
    

    但我总是犯这样的错误:

    Error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing
    
    1 回复  |  直到 4 年前
        1
  •  40
  •   Doug Stevenson    7 年前

    云自动运行 parses body content of known types . 如果您得到的是JSON,那么它已经被解析,并且可以在中使用 req.body . 您不需要添加其他主体解析中间件。

    如果需要处理原始数据,应该使用 req.rawBody ,但我认为你不需要在这里这么做。

        2
  •  17
  •   Pedro    5 年前

    下面是对我有用的代码:

    app.use(bodyParser.json({
      verify: function (req, res, buf) {
        var url = req.originalUrl;
        if (url.startsWith('/stripe')) {
           req.rawBody = buf.toString();
        }
      }
    }));
    

    然后通过req.rawBody进行验证

    stripe.checkWebHook(req.rawBody, signature);
    

    参考: https://github.com/stripe/stripe-node/issues/341

        3
  •  11
  •   MatiasG    5 年前

    添加此行:

    app.use('/api/subs/stripe-webhook', bodyParser.raw({type: "*/*"}))
    

    (第一个参数指定应该在哪个路由上使用原始主体解析器。请参阅 app.use() 参考文件。)

    就在这一行之前:

    app.use(bodyParser.json());
    

    (它不会影响您的所有操作,只是:'/api/subs/stripewebhook')

    注意:如果您使用的是Express 4.16+,则可以使用Express替换bodyParser:

    app.use('/api/subs/stripe-webhook', express.raw({type: "*/*"}));
    app.use(express.json());
    

    然后:

    const endpointSecret = 'whsec_........'
    
    const stripeWebhook = async (req, res) => {
        const sig = req.headers['stripe-signature'];
    
        let eventSecure = {}
        try {
            eventSecure = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
            //console.log('eventSecure :', eventSecure);
        }
        catch (err) {
            console.log('err.message :', err.message);
            res.status(400).send(`Webhook Secure Error: ${err.message}`)
            return
        }
        res.status(200).send({ received: true });
    }
    
        4
  •  3
  •   Fábio BC Souza    5 年前

    2021年-解决方案

    //App.js
    
    this.server.use((req, res, next) => {
      if (req.originalUrl.startsWith('/webhook')) {
        next();
      } else {
        express.json()(req, res, next);
      }
    });
    
    //routes.js
    
    routes.post(
      '/webhook-payment-intent-update',
      bodyParser.raw({ type: 'application/json' }),
    
      //your stripe logic (Im using a controller, but wherever)
      (req, res) => {
        stripe.webhooks.constructEvent(...)
      }
    )
    

    需要注意的两大警告:

    • 请务必发送电子邮件 req.headers['stripe-signature']
    • 确保您的 endpointSecret 是正确的,如果不是,它仍然会说同样的错误

    • 通过安装Stripe CLI进行本地测试: https://stripe.com/docs/webhooks/test

    • 在stripe dashboard上验证您的密钥,或者您也可以通过验证您的stripe日志来确保您的密钥是否正确,如下所示:

    webhook secret key example

    我希望这对你有帮助。:)

        5
  •  3
  •   Mohamed Jakkariya    5 年前
    // Use JSON parser for all non-webhook routes
    app.use(
      bodyParser.json({
        verify: (req, res, buf) => {
          const url = req.originalUrl;
          if (url.startsWith('/api/stripe/webhook')) {
            req.rawBody = buf.toString();
          }
        }
      })
    );
    

    对于上述答案,上面的代码看起来很好。但即使是我也犯了一个错误。放了同样的东西后,我也犯了同样的错误。

    最后,我已经弄清楚了,如果您在 rawBody 编码,然后它就会工作。

    这样地

    应用程序使用(
    bodyParser.json({
    if(url.startsWith('/api/stripe/webhook')){
    }
    }
    })
    );
    
    // Setup express response and body parser configurations
    app.use(express.json());
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));
    

    希望它能帮助别人。

        6
  •  2
  •   Muhammad Shahzad    5 年前

    Github answer

    const payload = req.body
    const sig = req.headers['stripe-signature']
    const payloadString = JSON.stringify(payload, null, 2);
    const secret = 'webhook_secret';
    const header = stripe.webhooks.generateTestHeaderString({
            payload: payloadString,
            secret,
    });
    
     let event;
     try {
          event = stripe.webhooks.constructEvent(payloadString, header, secret);
    
     } catch (err) {
            console.log(`Webhook Error: ${err.message}`)
            return res.status(400).send(`Webhook Error: ${err.message}`);
     }
    
       switch (event.type) {
           case 'checkout.session.completed': {
       ......
    enter code here
    
        7
  •  1
  •   marcolav    6 年前

    我能够从一个webhook获得数据,但不能从第二个webhook获得数据:问题是我使用的密钥与第一个webhook使用的密钥相同,但我发现每个webhook都有不同的密钥,这就是我获得相同消息的方式。

        8
  •  0
  •   Mark    6 年前

    在我重命名firebase云函数后,从Stripe仪表板发送测试webhook时,我就遇到了这种情况。我所有的其他功能都正常工作。通过在终端中重新设置解决 firebase函数:config:set stripe.webhook\u signature=“您的webhook签名秘密” (如果您正在使用)并重新部署功能 firebase部署--仅限函数

    第二次,我通过在stripe仪表板中滚动stripe签名解决了这个问题。

        9
  •  0
  •   Eng. Gathecha    5 年前

    请使用此脚本

    app.use(
      bodyParser.json({
        verify: (req, res, buf) => {
          req.rawBody = buf;
        },
      })
    );