将数据发布到 odata 服务时,nodejs 中的 CSRF 令牌验证失败

问题描述 投票:0回答:2
var request = require('request');
var username = '';
var password = '';
var url = 'http://207.188.73.88:8000/sap/opu/odata/sap/ZTEE_TIME_SRV/ZTEERESERVESet(Time=time\'PT11H00M00S\',Date=datetime\'2014-03-11T00%3A00%3A00\',Location=\'TAJ\',Number=3)';
var auth = 'Basic ' + new Buffer(username + ':' + password).toString('base64');

// i am trying to post data to odata service but the problem is that i could not get valid token from get service to use it in the post method i am first send get method

request(
  {
    url: url,
    headers: {
      'Authorization': auth,
      'x-csrf-token': 'Fetch',
    },
  },
  function(error, response, body) {
    console.log('JSON data ' + response);
    console.log('body' + body);
    // trying to get the token to use in post
    console.log(response.headers);

    request(
      {
        url: url,
        headers: {
          here it says invalid token
          'Authorization': auth,
          'X-CSRF-TOKEN': 'u6piLO58XoK6udOkQ5Naww==',
        },
        method: 'POST',
        //Lets post the following key/values as form
        form: {
          Time: 'PT11H00M00S',
          Date: '2014-03-11T00%3A00%3A00',
          Location: 'TAJ',
          Number: 3,
        },
      },
      function(error, response, body) {
        console.log(body);
      },
    );
  },
);
node.js post odata token csrf
2个回答
2
投票

我找到了解决方案。

我尝试使用 POSTMAN 来完成此操作,效果很好。 问题是,当我要求 CSRF 令牌时,它总是给我同样的回报。 但是当我尝试使用节点时,每次都不一样。然后我意识到饼干不见了。

仅此而已,解决方案是至少在

cookie
请求中发送
POST

set-cookie
请求的
"Fetch"
必须在
Post
请求中作为
Cookie
旁边的
x-csrf-token

发送

我把例子放在typescript中,但是在js中并没有太大变化,想法是一样的。

该示例不是最好的情况,但足以弄清楚它是如何工作的

let headers = {
  "Authorization": "Basic " + new Buffer(username + ":" + password).toString("base64"),
  "Content-Type":"application/json",
  "Accept":"application/json",
  "x-csrf-token":"Fetch" // get CSRF Token for post or update
};
// if you are using session vars
if (req.session.headers && req.session.headers.cookie) {
  headers['Cookie'] = req.session.headers.cookie;
} else {
  req.session.headers = {}; // initialize as object
}
let opts = {
  url: "https://{host}:{port}/sap/opu/odata/sap/MD_SUPPLIER_MASTER_SRV",
  qs: params1, // params set before, not set in the example
  headers: headers,
  json: true, 
}
request(opts, (error: any, response: any, body: any): any => {
  if (!error && response.statusCode === 200) {
    if (response.headers["set-cookie"]) { 
      req.session.headers.cookie = response.headers["set-cookie"]; // store Cookie in session
      headers['Cookie'] = req.session.headers.cookie; // set in headers for the next call. I guess this is the part you missed
    }
    if (response.headers['x-csrf-token']) {
      req.session.headers.csrf = response.headers['x-csrf-token']; // store csrf-token in session
      headers['x-csrf-token'] = req.session.headers.csrf; // set in headers for the next call
    }

    let options: request.Options = {
      url: "https://{host}:{port}/sap/opu/odata/sap/MD_SUPPLIER_MASTER_SRV/C_BusinessPartnerSupplierEdit",
      method: 'POST',
      headers: headers,
      qs: params2, // params set before
      json: true,
    }
    request(options, (error: any, response: any, body: any): any => {
      res.json(body);
    });
  }
});

问候


0
投票

感谢@subhan 提出的问题和@Mikel 的回答。 我正在使用 SAP CAP,我希望这会自动处理。 同样的事情也发生在我身上:在 Postman 上工作,但在服务器上不行。

通过在模拟服务上本地工作的默认实现,我可以简单地连接到该服务并创建一个新实体:

const bupa = await cds.connect.to('API_BUSINESS_PARTNER');
...
const result = await bupa.create('A_BusinessPartner',newBupa);

我的旅程是使用 SAP CAP 的 .send() 来添加更多标头,但它不允许我获取响应标头,然后使用 SAP Cloud SDK 的 http-client,我尝试使用库的 csrf 选项,最后使用 Node 的 https (以及 - 30 分钟后 - 不是 http),我可以更好地访问请求属性。最终,我回到这篇文章并使其发挥作用。

我缺少的一件事是“Cookie”标头。我已经发送了“set-cookie”和自己的“x-csrf-token”,但这还不够。 (毕竟不需要“set-cookie”。)

这是生成的 SAP CAP 代码:

const cds = require('@sap/cds');
const { executeHttpRequest } = require('@sap-cloud-sdk/http-client');

// ...

let filledHeaders = {};
const fetchHeader = { "x-csrf-token": "fetch" };
const result = await executeHttpRequest({
    destinationName: cds.requires.API_BUSINESS_PARTNER.credentials.destination
  },{
    method: 'GET',
    url: cds.requires.API_BUSINESS_PARTNER.credentials.path + '/A_BusinessPartner?$top=1',
    headers: fetchHeader
  });
filledHeaders['Cookie'] = result.headers["set-cookie"];
filledHeaders['x-csrf-token'] = result.headers['x-csrf-token'];
console.log(filledHeaders); // in case you want to inspect
Object.assign(req.headers, filledHeaders);

// connect to the service
const bupa = await cds.connect.to('API_BUSINESS_PARTNER');

// send the request with the custom headers
const result = await bupa.send('POST', 'A_BusinessPartner', req.data.newBupa, req.headers);
console.log(result);

一些注意事项:

  • 我正在 S/4HANA Cloud 上使用 业务合作伙伴 (A2X) API。
  • 我在 S/4HANA Cloud 上创建了一个通信,并在 SAP BTP 上创建了相应的目标。此代码适用于 BTP 或混合测试
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.