Node.js 如何使用etrade api对请求令牌的oauth签名进行签名?

Node.js 如何使用etrade api对请求令牌的oauth签名进行签名?,node.js,oauth,crypt,etrade-api,Node.js,Oauth,Crypt,Etrade Api,我正在尝试为一个项目连接eTrade的API。它们使用OAuthV1流。在流程的第一步——获取请求令牌时,我遇到了错误。可以找到他们文档中的信息 我得到的错误是401-签名无效 我一直在阅读OAuth流,并且已经熟悉了这个过程。在过去,我使用PassportJS进行第三方集成 所以eTrade为我提供了4个密钥-PROD_密钥、PROD_SECRET、SANDBOX_密钥、SANDBOX_SECRET。我现在正在使用沙盒密钥,因为我的生产密钥仍处于挂起状态 现在我的API上有了一个端点,我将从我

我正在尝试为一个项目连接eTrade的API。它们使用OAuthV1流。在流程的第一步——获取请求令牌时,我遇到了错误。可以找到他们文档中的信息

我得到的错误是401-签名无效

我一直在阅读OAuth流,并且已经熟悉了这个过程。在过去,我使用PassportJS进行第三方集成

所以eTrade为我提供了4个密钥-PROD_密钥、PROD_SECRET、SANDBOX_密钥、SANDBOX_SECRET。我现在正在使用沙盒密钥,因为我的生产密钥仍处于挂起状态

现在我的API上有了一个端点,我将从我的客户机调用它来获取请求令牌。它的结构是这样的:

router.route('/auth/request').get(controller.request);
// controllers/auth.js

const axios = require('axios');
const { v1 } = require('uuid');
const crypto = require('crypto');

function generateSignature() {
  const method = 'GET',
        url = 'http://localhost/',
        encodedUrl = encodeURIComponent(url),
        paramaters = {
          oauth_consumer_key: process.env.ETRADE_SANDBOX_API_KEY,
          oauth_signature_method: 'HMAC-SHA1',
          oauth_timestamp: Math.floor(Date.now() / 1000),
          oauth_nonce: v1(),
          oauth_callback: 'oob'
        }

  var ordered = {};
  Object.keys(paramaters).sort().forEach((key) => {
    ordered[key] = paramaters[key];
  });

  var encodedParameters = '';

  for(k in ordered) {
    const encodedValue = escape(ordered[k]);
    const encodedKey = encodeURIComponent(k);

    if(encodedParameters === '') {
      encodedParameters += encodeURIComponent(`${encodedKey}=${encodedValue}`);
    } else {
      encodedParameters += encodeURIComponent(`&${encodedKey}=${encodedValue}`);
    }
  }

  encodedParameters = encodeURIComponent(encodedParameters);

  const signature_base_string = `${method}&${encodedUrl}&${encodedParameters}`;
  const signing_key = `${process.env.ETRADE_SANDBOX_SECRET_KEY}`;
  const signature = crypto.createHmac("SHA1", signing_key).update(signature_base_string).digest().toString('base64');
  const encodedSignature = encodeURIComponent(signature);

  return encodedSignature;
}

module.exports = {
  request: async (req, res) => {
    console.log('Fetching request token from etrade...');

    try {
      var response = await axios.get(`https://api.etrade.com/oauth/request_token`, {
        params: {
          oauth_consumer_key: process.env.ETRADE_SANDBOX_API_KEY,
          oauth_signature_method: 'HMAC-SHA1',
          oauth_signature: generateSignature(),
          oauth_timestamp: Math.floor(Date.now() / 1000),
          oauth_nonce: v1(),
          oauth_callback: 'oob'
        }
      });

      console.log('Fetched request token...', response.data);
    } catch (error) {
      console.log('Could not fetch request token...', error.response.data);
    }
  }
}
下面的控制器就是我生成签名并尝试从eTrade请求令牌的地方。该控制器如下所示:

router.route('/auth/request').get(controller.request);
// controllers/auth.js

const axios = require('axios');
const { v1 } = require('uuid');
const crypto = require('crypto');

function generateSignature() {
  const method = 'GET',
        url = 'http://localhost/',
        encodedUrl = encodeURIComponent(url),
        paramaters = {
          oauth_consumer_key: process.env.ETRADE_SANDBOX_API_KEY,
          oauth_signature_method: 'HMAC-SHA1',
          oauth_timestamp: Math.floor(Date.now() / 1000),
          oauth_nonce: v1(),
          oauth_callback: 'oob'
        }

  var ordered = {};
  Object.keys(paramaters).sort().forEach((key) => {
    ordered[key] = paramaters[key];
  });

  var encodedParameters = '';

  for(k in ordered) {
    const encodedValue = escape(ordered[k]);
    const encodedKey = encodeURIComponent(k);

    if(encodedParameters === '') {
      encodedParameters += encodeURIComponent(`${encodedKey}=${encodedValue}`);
    } else {
      encodedParameters += encodeURIComponent(`&${encodedKey}=${encodedValue}`);
    }
  }

  encodedParameters = encodeURIComponent(encodedParameters);

  const signature_base_string = `${method}&${encodedUrl}&${encodedParameters}`;
  const signing_key = `${process.env.ETRADE_SANDBOX_SECRET_KEY}`;
  const signature = crypto.createHmac("SHA1", signing_key).update(signature_base_string).digest().toString('base64');
  const encodedSignature = encodeURIComponent(signature);

  return encodedSignature;
}

module.exports = {
  request: async (req, res) => {
    console.log('Fetching request token from etrade...');

    try {
      var response = await axios.get(`https://api.etrade.com/oauth/request_token`, {
        params: {
          oauth_consumer_key: process.env.ETRADE_SANDBOX_API_KEY,
          oauth_signature_method: 'HMAC-SHA1',
          oauth_signature: generateSignature(),
          oauth_timestamp: Math.floor(Date.now() / 1000),
          oauth_nonce: v1(),
          oauth_callback: 'oob'
        }
      });

      console.log('Fetched request token...', response.data);
    } catch (error) {
      console.log('Could not fetch request token...', error.response.data);
    }
  }
}

我已按照internet上的一些指南来帮助我理解签署请求的过程,但我似乎无法获得有效的回复。

您的代码针对的是etrade产品URL。尝试调用沙盒URL

Production  https://api.etrade.com/v1/{module}/{endpoint}
Sandbox     https://apisb.etrade.com/v1/{module}/{endpoint}

我不知道你是否还在寻找这个问题的答案,但我认为以下内容可能会有所帮助。我在尝试与他们的API集成时遇到了类似的问题(不过我使用的是java)。查看他们的示例代码,我意识到签名基串的键需要在request_token API的末尾附加一个“&”。请参阅其示例应用程序中的以下代码-

if(令牌!=null){
//不适用于请求\u令牌API调用
key=StringUtils.isEmpty(token.getOauth\u token\u secret())?context.getresources().getSharedSecret()+“&”:
context.getResources().getSharedSecret()+“&”+OAuth1Template.encode(token.getOauth_token_secret());
}否则{
//适用于请求\u令牌API调用
key=context.getResources().getSharedSecret()+“&”;
}
好了,这不是oAuth标准或任何东西。这似乎是非常具体的执行。无论如何,我更新了我的代码,在末尾添加了额外的“&”,它开始工作了

私有字符串signBaseString(字符串httpMethod,字符串url){
StringBuilder baseString=新的StringBuilder();
baseString.append(encode(httpMethod)).append(“&”).append(encode(url)).append(“&”);
追加(编码(normalizeParams(url));
//额外的&在这里添加。
SecretKeySpec signingKey=新的SecretKeySpec((this.apiSecret+“&”).getBytes(),SIGN_ALG);
Mac=null;
试一试{
mac=mac.getInstance(SIGN\u ALG);
mac.init(签名密钥);
返回新字符串(Base64.encodeBase64(
mac.doFinal(baseString.toString().getBytes(
标准字符集(UTF_8));
}捕获(NoSuchAlgorithmException | InvalidKeyException e){
logger.error(“签名头时出错”,e);
返回null;
}
}

让我知道这是否适用于您。

他们不像其他端点那样为请求令牌端点定义沙盒url。我尝试了apisb.etrade.com/oauth/request_令牌,但得到了相同的错误。我会再试一次谢谢我一定会让你知道的