Salesforce Apex Http 请求 - REST + OAUTH 1.0

问题描述 投票:0回答:1

我正在尝试通过 Salesforce 与 REST API 进行通信。 我有一个邮递员集合,工作得很好,但是当尝试使用 apex 复制它时,我收到状态 400(错误请求)错误。

URL 已在远程站点设置中注册。 这是我的代码(我不允许发布参数,但相信我它们与邮递员集合相同):

public static void testCode(){
    Http http = new Http();
    HttpRequest request = new HttpRequest();
    request.setEndpoint('<API URL>?script=1022&deploy=1');
    request.setMethod('POST');
    request.setHeader('Content-Type', 'application/json');
    String nonce     = String.valueOf(Crypto.getRandomLong());
    String timestamp = String.valueOf(DateTime.now().getTime() / 1000);
    String consumerSecret = '<SECRET>';

    String header = 'OAuth ';
    header+= 'realm="8305111_SB1", ';
    header+= 'oauth_signature_method="HMAC-SHA1"';
    header+= 'oauth_consumer_key="<KEY>", ';
    header+= 'oauth_token="<TOKEN>", ';
    header+= 'oauth_token_secret="<TOKEN>", ';
    header+= 'oauth_version="1.0", ';
    header+= 'oauth_timestamp="'+timestamp+'", ';

    header+= 'oauth_nonce="'+nonce+'", ';
    Map<String,String> parameters = new Map<String,String>();
    parameters.put('realm','8305111_SB1');
    parameters.put('oauth_signature_method','HMAC-SHA1');
    parameters.put('oauth_consumer_key','<KEY>');
    parameters.put('oauth_token','<TOKEN>');
    parameters.put('oauth_token_secret','<SECRET>');
    parameters.put('oauth_version','1.0');
    parameters.put('oauth_timestamp',timestamp);
    parameters.put('oauth_nonce',nonce);
    header += 'oauth_signature="'+generateSignature(request, consumerSecret, parameters)+'"';


    request.setHeader('Authorization', header);

    request.setBody('{"Mundo": "Mundo"}');
    System.Debug('AUTH HEADER:');
    for(String s : header.Split(',')){System.Debug(s);}
    System.Debug('BODY: '+request.getBody());
    System.debug('REQUEST  --> '+request);
    System.debug('RESPONSE --> '+http.send(request));
}

private static String generateSignature(HttpRequest req, String consumerSecret, Map<String,String> parameters) {
    String s = createBaseString(parameters,req);
    Blob sig = Crypto.generateMac( 'HmacSHA1', Blob.valueOf(s), Blob.valueOf(consumerSecret) );
    return EncodingUtil.urlEncode(EncodingUtil.base64encode(sig), 'UTF-8');
}

private static String createBaseString(Map<String,String> oauthParams, HttpRequest req) {
    Map<String,String> p = oauthParams.clone();
    if(req.getMethod().equalsIgnoreCase('post') && req.getBody()!=null &&
        req.getHeader('Content-Type')=='application/x-www-form-urlencoded') {
        p.putAll(getUrlParams(req.getBody()));
    }
    String host = req.getEndpoint();
    Integer n = host.indexOf('?');
    if(n>-1) {
        p.putAll(getUrlParams(host.substring(n+1)));
        host = host.substring(0,n);
    }
    List<String> keys = new List<String>();
    keys.addAll(p.keySet());
    keys.sort();
    String s = keys.get(0)+'='+p.get(keys.get(0));
    for(Integer i=1;i<keys.size();i++) {
        s = s + '&' + keys.get(i)+'='+p.get(keys.get(i));
    }

    // According to OAuth spec, host string should be lowercased, but Google and LinkedIn
    // both expect that case is preserved.
    return req.getMethod().toUpperCase()+ '&' + EncodingUtil.urlEncode(host, 'UTF-8') + '&' + 
    EncodingUtil.urlEncode(s, 'UTF-8');
}

private static Map<String,String> getUrlParams(String value) {

    Map<String,String> res = new Map<String,String>();
    if(value==null || value=='') {
        return res;
    }
    for(String s : value.split('&')) {
        System.debug('getUrlParams: '+s);
        List<String> kv = s.split('=');
        if(kv.size()>1) {
            // RFC 5849 section 3.4.1.3.1 and 3.4.1.3.2 specify that parameter names
            // and values are decoded then encoded before being sorted and concatenated
            // Section 3.6 specifies that space must be encoded as %20 and not +
            String encName = EncodingUtil.urlEncode(EncodingUtil.urlDecode(kv[0], 
                             'UTF-8'), 'UTF-8').replace('+','%20');
            String encValue = EncodingUtil.urlEncode(EncodingUtil.urlDecode(kv[1], 'UTF-8'), 
            'UTF-8').replace('+','%20');
            //System.debug('getUrlParams:  -> '+encName+','+encValue);
            res.put(encName,encValue);
        }
    }
    return res;
}
rest salesforce apex
1个回答
0
投票

如果它不是一个公共 API,你会遇到困难,互联网上的陌生人无法复制你正在做的事情;)考虑将这些请求发送到某些服务,如 requestbin、httpbin 等(或者也许你有自己的网络服务器,你可以仅用于记录请求...我认为其中一些是付费的,继续谷歌搜索)。比较从 apex 发出的内容与邮递员发送的内容?

假设它们确实相同 - 供应商可能正在做一些 IP 白名单吗?也许他们需要将 Salesforce IP 地址列入白名单(或者他们可能禁止 AWS,而你在 hyperforce 组织中)

© www.soinside.com 2019 - 2024. All rights reserved.