NetSuite OAuth1.0中InvalidSignature问题

news/2024/11/24 15:50:06/

本周闭关写代码,用Java通过TBA方式访问NetSuite REST Webservices。由于是手生,卡在InvalidSignature报错上,在这个问题上被卡了一整天。

 直到终于到来的Aha时刻。

在NetSuite中的样例代码是PHP的, 我平移到Java后,代码逻辑丝毫未变。反复核对代码后,发现代码没有任何的问题。按照NetSuite系统的指引,签名流程如下:

1. 构建Base String。这时,请注意字符串的格式,有三种格式。我采用的是REST Webservices,所以按照相应指引进行了构建。

NetSuite Applications Suite - The Signature for Web Services and RESTletshttps://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_1534941088.html#The-Signature-for-Web-Services-and-RESTlets

2. 构建Secret。

3. 用Secret对Base String进行加密,形成Signature。加密方法为HMAC-SHA256。

4. 把Signature结合其他字串,形成Authorization字串,赋给Header。

反复检查上述逻辑,但是一直报InvalidSignature错。相同的参数,在Postman中是毫无问题的。我们在对比了Header中的Authorization字符串后,发现只有最后的oauth_signature的值是有差别的。

 

 Signature的差别,只会有两种可能性,一是加密方法出错,二是Base String出错。在确定了HmacSHA256没有问题后,我们把问题聚焦在了Base String。

最后,虫子找到了!

原来在OAuth1.0的规范中,host必须是小写的。例如,123456-SB1必须格式化为123456-sb1。

 但是,在构建的Header中,Host是要大写的。这就是大坑所在。

以下代码调试通过,可参考。

//访问NetSuite REST Webservices,请注意Base String中Host的小写格式。
//Rick Mao 2023-6-26import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.net.URLEncoder;
import java.util.*;public class MainAppOAuth1okhttp3 {private static final String NETSUITE_ACCOUNT = "你的账户"; //对字母大写private static final String NETSUITE_CONSUMER_KEY = "你的consumer key";private static final String NETSUITE_CONSUMER_SECRET = "你的consumer secret";private static final String NETSUITE_TOKEN_ID = "你的token id";private static final String NETSUITE_TOKEN_SECRET = "你的token secret";// Generate the timestamp and nonceprivate static final String timestamp = Long.toString(System.currentTimeMillis() / 1000L);private static final String nonce = UUID.randomUUID().toString();public static void main(String[] args) throws Exception {// Create OkHttpClient with logging interceptor for debuggingHttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(loggingInterceptor).build();// Create the request URLHttpUrl requestUrl = HttpUrl.parse("https://" + NETSUITE_ACCOUNT + ".suitetalk.api.netsuite.com/services/rest/record/v1/customer");// Generate the Authorization header valueString authorizationHeader = generateAuthorizationHeader(requestUrl.toString());// Create the requestRequest request = new Request.Builder().url(requestUrl).header("Authorization", authorizationHeader).get().build();// Execute the requesttry (Response response = httpClient.newCall(request).execute()) {// Process the responseString responseBody = response.body().string();System.out.println(responseBody);}}private static String generateAuthorizationHeader(String url) throws Exception {// Generate the base string,这是Rest Webservice格式的,SOAP和Restlet则不同String baseString = baseStringConcat();// Generate the signatureString signature = generateSignature(baseString, NETSUITE_CONSUMER_SECRET, NETSUITE_TOKEN_SECRET);// Construct the Authorization header valueString AuthString = "OAuth " +"realm=\"" + NETSUITE_ACCOUNT + "\"," +"oauth_consumer_key=\"" + NETSUITE_CONSUMER_KEY + "\"," +"oauth_token=\"" + NETSUITE_TOKEN_ID + "\"," +"oauth_signature_method=\"HMAC-SHA256\"," +"oauth_timestamp=\"" + timestamp + "\"," +"oauth_nonce=\"" + nonce + "\"," +"oauth_version=\"1.0\"," +"oauth_signature=\"" + URLEncoder.encode(signature, StandardCharsets.UTF_8) + "\"";return AuthString;}private static String generateSignature(String baseString, String consumerSecret, String tokenSecret) throws NoSuchAlgorithmException, InvalidKeyException {String EMPTY_STRING = "";String CARRIAGE_RETURN = "\r\n";String key = URLEncoder.encode(consumerSecret, StandardCharsets.UTF_8) + "&" + URLEncoder.encode(tokenSecret, StandardCharsets.UTF_8);SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");Mac sha256Hmac = Mac.getInstance("HmacSHA256");sha256Hmac.init(secretKey);byte[] signatureBytes = sha256Hmac.doFinal(baseString.getBytes(StandardCharsets.UTF_8));String resultSignature = new String(java.util.Base64.getEncoder().encode(signatureBytes));return resultSignature.replace(CARRIAGE_RETURN, EMPTY_STRING);}public static String generateSignatureBaseString(String httpMethod, String url, Map<String, String> parameters) throws Exception {StringBuilder baseString = new StringBuilder();// URL-encode the components of the URLString encodedUrl = URLEncoder.encode(url, StandardCharsets.UTF_8);// Sort and encode the parametersMap<String, String> sortedParameters = new HashMap<>(parameters);sortedParameters.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(entry -> {try {String key = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8);String value = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8);baseString.append(key).append("=").append(value).append("&");} catch (Exception e) {e.printStackTrace();}});// Remove the trailing '&' characterif (baseString.length() > 0) {baseString.setLength(baseString.length() - 1);}// Construct the signature base stringString signatureBaseString = httpMethod.toUpperCase() + "&" + encodedUrl + "&" + URLEncoder.encode(baseString.toString(), "UTF-8");return signatureBaseString;}private static String baseStringConcat() throws Exception {String httpMethod = "GET";//NETSUITE_ACCOUNT 需要转为小写,否则服务端报InvalidSignature错。String url = "https://"+ NETSUITE_ACCOUNT.toLowerCase() + ".suitetalk.api.netsuite.com/services/rest/record/v1/customer";Map<String, String> parameters = new HashMap<>();parameters.put("oauth_consumer_key", NETSUITE_CONSUMER_KEY);parameters.put("oauth_nonce", nonce);parameters.put("oauth_signature_method", "HMAC-SHA256");parameters.put("oauth_timestamp", timestamp);parameters.put("oauth_token", NETSUITE_TOKEN_ID);parameters.put("oauth_version", "1.0");String signatureBaseString = generateSignatureBaseString(httpMethod, url, parameters);System.out.println(signatureBaseString);return signatureBaseString;}
}

如果有任何关于NetSuite的问题,欢迎来谈。我的邮箱:rick.mao@truston.group


http://www.ppmy.cn/news/588499.html

相关文章

瑞星杀毒软件2008下载版,附用户ID及序列号

瑞星杀毒软件下载 软件大小&#xff1a;61983KB 软件类别&#xff1a;国产软件/病毒防治 下载次数&#xff1a;24485886 软件授权&#xff1a;免费版 软件语言&#xff1a;简体中文 运行环境&#xff1a;Win9x/Me/NT/2000/XP/2003 软件评级&#xff1a; 五星 更新时间&a…

瑞星网络版

代社区NIq1^ r$Apq g 声明&#xff1a;企业、公司等赢利性单位&#xff08;目标比较大&#xff09;还是用正版吧免得惹麻烦&#xff0c;一般的内部局域网&#xff0c;校园网的网管可以试试。 bbs.mt30.comf_&QZa5h,m6Y 安装有问题请提出&#xff0c;我已经在350台电脑的局域…

携世界级核心技术 瑞星杀毒软件2007版全球发行

,国内最大的信息安全厂商瑞星召开盛大的发布会,隆重推出年度旗舰级新品——“瑞星杀毒软件 2007版”,该产品在全球安全业界首次将商用“虚拟机”技术应用到杀毒引擎中,结合Startup Scan(抢先杀毒)、未知病毒查杀等技术,对“多重加壳”等恶性顽固病毒的查杀能力实现重大突破,整体…

瑞星杀毒助手 升级到 0.1.0020版

更新&#xff1a; 日期版本说明2006.01.010.1.0020&#xff08;14,336字节&#xff09;1.添加右键调用系统关联菜单&#xff0c;支持病毒文件打包2.修正前一版本右键显示属性的1个bug 详情请参阅&#xff1a; 瑞星杀毒助手 升级到 0.1.0020版

瑞星网络版杀毒软件安装部署

一、安装 瑞星杀毒软件网络版是由四个相互关联的子系统组成。安装对象包括“系统中心的安装”、“服务器端的安装”、“客户端的安装”和“管理员控制台的安装”。安装首先是在服务器上安装“系统中心”,然后才能进行其它三个模块的安装。 一、系统中心和服务器端的安装 系统中…

快速获取瑞星杀毒软件一年免费版

瑞星提示 需要点击“瑞星卡卡6.0”主页面的标签“杀毒软件”和“防火墙”&#xff0c;按照系统提示操作&#xff0c;可获得相应产品的一年免费使用权。 实际上直接下载即可&#xff0c;用迅雷下载更好&#xff0c;速度。。。 下载地址&#xff1a;http://rsdownload.rising.c…

国产管理软件勒索病毒大爆发

国内知名技术社区http://qidao123.com最新消息&#xff0c;国内多个安全技术社群传出今天针对以疑似用友为代表的国产管理软件勒索病毒大爆发 在http://qidao123.com的运维社群&#xff0c;有群友爆料 勒索病毒都懒得攻击的惠普老服务器&#xff1f; 前几天宁波一家公司的用友…

瑞星杀毒软件 v2006 18.30.10 特别版(更新06月06日病毒库)

瑞星杀毒软件2006&#xff0c;它是瑞星公司最新研制的OOT引擎占用资 源更少&#xff0c;查杀速度更快。瑞星通过独有的行为模式分析 &#xff08;BMAT&#xff09;和脚本判定&#xff08;SVM&#xff09;两项查杀病毒技术实现对未知 病毒进行检测&#xff0c;该技术已经获得…