微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

具有摘要身份验证问题的 Google App Script 提取请求

如何解决具有摘要身份验证问题的 Google App Script 提取请求

我正在尝试使用 GAS 的 UrlFetchApp 从 HIK Vision 的摄像头系统 DVR 中检索一些信息。我能够使用 Postman 执行成功的请求,但无法将其与 Google App Script 的 UrlFetchApp.fetch 一起使用。我确认我的摘要计算是正确的。我通过将 GAS 中的 nonce、cnonce、qop 等值替换为 Postman 中的值并获得与 Postman 相同的响应字符串来做到这一点。请参阅下面的邮递员图片

Postman's request/response

Postman 收到 200 条响应以及我需要的所有数据。

我的应用程序的工作方式是发送第一个请求并获得 401 响应。然后它发送第二个请求,并带有根据从第一个请求接收到的数据计算出的 auth 标头。无论我做什么,我总是得到 401。我在标题属性等中使用了双引号。

代码如下:

function getRecordedDaysCount(){
  
  const url = 'my_server_url';

  const userName = 'user';
  const pass = "password";
  const uri = "/ISAPI/ContentMgmt/record/tracks/101/dailydistribution";
  const method = "POST"
  const updatedUrl = url + uri;      

  let year = '2021';
  let month = '03';

  //payload required by the server for this request
  let payload = '<?xml version: "1.0" encoding="utf-8"?><trackDailyParam><year>' + year + '</year><monthOfYear>' + month + '</monthOfYear></trackDailyParam>';

  let options = {
    "method" : method,"muteHttpExceptions": true,"headers":{    
     "Accept": "application/xml,text/plain,*/*",}
  }

  let data = UrlFetchApp.fetch(updatedUrl,options);      
  
  if(data.getResponseCode() == 401){
    let wwwAuthenticate = data.getAllHeaders()["WWW-Authenticate"];
    
    // Example WWWAuthenticate
    // "Digest realm="493b21e13dddb4ef7745edaa",domain="::",qop="auth",//  nonce="17fbf10682dc4a7ceb04206cbcd95d8d:1616709300571",opaque="",algorithm="MD5",stale="FALSE""

    let authData = wwwAuthenticate.split(',');
    let authType = authData[0].split(' ')[0];    // Digest
    if(authType === "Digest"){
      let realm = authData[0].split('"')[1];     // "493b21e13dddb4ef7745edaa"
      let qop=authData[2].split('"')[1];         // "auth"
      let nonce =  authData[3].split('"')[1];    // "17fbf10682dc4a7ceb04206cbcd95d8d:1616709300571"
      let algorithm = authData[5].split('"')[1]; // "MD5"
      let nc="00000001";
      let cnonce= new Date().getTime().toString(16);

      let hash1 = signMD5(userName +':'+ realm +':'+ pass);
      let hash2 = signMD5(method+':'+ uri);
      let response = signMD5(hash1+':'+nonce+':'+nc+':'+cnonce+':'+qop+':'+hash2); 

      let digestAuth =  "Digest username=\"" + userName + "\"" +
                          ",realm=\"" + realm + "\"" +
                          ",nonce=\"" + nonce + "\"" +
                          ",uri=\"" + uri + "\"" + 
                          ",qop=auth" +
                          ",nc=" + nc +
                          ",algorithm=\"MD5\"" +
                          ",cnonce=\"" + cnonce + "\"" +                          
                          ",response=\"" + response + "\"";

      let headers = {
        "Content-Type": "text/plain",// copied from Postman
        "Accept-Encoding": "gzip,deflate,br",// copied from Postman
        "Authorization": digestAuth,}

      let options = {
        "method" : method,"headers": headers,"payload": (payload)
      }
    
      logUrlFetch(updatedUrl,options);
        
    }
  }
}


function signMD5(message){     
  let signature = Utilities.computeDigest(
                       Utilities.DigestAlgorithm.MD5,message,Utilities.Charset.UTF_8);
  
  let signatureStr = '';
    for (i = 0; i < signature.length; i++) {
      let byte = signature[i];
      if (byte < 0)
        byte += 256;
      let byteStr = byte.toString(16);
      // Ensure we have 2 chars in our byte,pad with 0
      if (byteStr.length == 1) byteStr = '0'+byteStr;
      signatureStr += byteStr;
    }   
  Logger.log(signatureStr);
  return signatureStr;
}

function logUrlFetch(url,opt_params) {
  let params = opt_params || {};
  params.muteHttpExceptions = true;
  let request = UrlFetchApp.getRequest(url,params);
  Logger.log('Request:       >>> ' + JSON.stringify(request));
  let response = UrlFetchApp.fetch(url,params);
  Logger.log('Response Code: <<< ' + response.getResponseCode());
  Logger.log('Response text: <<< ' + response.getContentText());
  if (response.getResponseCode() >= 400) {
    throw Error('Error in response: ' + response);
  }
  return response;
}

这些是我得到的日志:

firs request log

second request log

我多次比较了 Postman 和我的应用程序中的标头,它们大体相同但存在一些差异。 UrlFetchApp.fetch 向请求添加了一些标头,但是我也在 Postman 中添加了它们,它仍然有效,所以我得出结论,这些额外的标头不是问题。此外,UrlFetchApp.fetch 将请求方法发送为“post”(小写),邮递员使用全部大写 - 'POST'。 http方法是Digest HA2计算的一部分,区分大小写。这是我对为什么我的请求不起作用的唯一想法。我将我的应用程序的方法更改为小写“post”以用于摘要计算和标题,但这没有帮助。

除了 UrlFetchApp.fetch 之外,还有其他方法可以在 Google App Script 中发送请求吗? 非常感谢!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。