Java TBA访问NetSuite Restlet时的403错误

本周有同学问为啥Java访问NetSuite Restlet时,按照知识会之前的文章分享,会一直报403 INVALID_LOGIN_ATTEMPT错误。

https://nk-community.blog.csdn.net/article/details/131399801icon-default.png?t=N7T8https://nk-community.blog.csdn.net/article/details/131399801原因是之前的文章是基于访问REST Webservice的场景,由于访问Restlet时是有些细微区别的,照搬代码是会报错的。这个区别在于Base String的构建。

通过TBA访问NetSuite的服务时,不同的服务其对Base String的格式要求是有不同的。SOAP Webservice, REST Webservice,Restlet三种各不相同。

区别于REST Webservice的是,Restlet的Base String需要加上deploy和script参数。

下面附上调试通过的Java脚本,请参考。

//访问NetSuite Restlet,请注意Base String中Host的小写格式。
//Rick Mao 2024-1-5import 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 NetSuiteRestletAccess {private static final String NETSUITE_ACCOUNT = "XXX"; //对字母大写private static final String NETSUITE_CONSUMER_KEY = "XXX";private static final String NETSUITE_CONSUMER_SECRET = "XXX";private static final String NETSUITE_TOKEN_ID = "XXX";private static final String NETSUITE_TOKEN_SECRET = "XXX";// 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 + ".restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=1795&deploy=1");// 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 {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() + ".restlets.api.netsuite.com/app/site/hosting/restlet.nl";Map<String, String> parameters = new HashMap<>();parameters.put("deploy", "1"); //Restlet访问专用,deploy id需具实际调整。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");parameters.put("script", "1795");//Restlet访问专用,script id需具实际调整。String signatureBaseString = generateSignatureBaseString(httpMethod, url, parameters);System.out.println(signatureBaseString);return signatureBaseString;}
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/598135.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线程同步之:QReadWriteLock

1、 使用互斥量QMutex时候存在一个问题 每次只能有一个线程获得互斥量的权限。如果在一个程序中有多个线程“读”取某个变量&#xff0c;使用互斥量时也必须排队&#xff01; 然而&#xff0c;实际情况是允许&#xff1a;让多个线程同时“读”&#xff01; 这样互斥量 就会降…

面试官:说说flexbox(弹性盒flex布局),以及适用场景?

面试官&#xff1a;说说flexbox&#xff08;弹性盒布局模型&#xff09;,以及适用场景&#xff1f; 一、是什么 Flexible Box 简称 flex&#xff0c;意为”弹性布局”&#xff0c;可以简便、完整、响应式地实现各种页面布局 采用Flex布局的元素&#xff0c;称为flex容器conta…

面试官:线程池的7种创建方式,你都清楚吗?

文章目录 前言1. 固定数量的线程池a. 线程池返回结果b. ⾃定义线程池名称或优先级 2. 带缓存的线程池3. 执⾏定时任务a. 延迟执行(一次)b. 固定频率执行c. scheduleAtFixedRate VS scheduleWithFixedDelay 4. 定时任务单线程5. 单线程线程池6. 根据当前CPU⽣成线程池 前言 线程…

CRM管理系统八大特性,如何帮助企业提升业务效能?

CRM管理系统的使用率逐年上升&#xff0c;这离不开企业对客户的依赖——管理好客户关系是企业发展你的重要因素&#xff0c;由此可见CRM对于任何成长中的企业都是必不可少的。以前我们写过很多关于CRM功能的文章&#xff0c;这篇文章换个思路&#xff0c;想一想CRM管理系统主要…

Pytorch从零开始实战15

Pytorch从零开始实战——ResNeXt-50算法实战 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNeXt-50算法实战环境准备数据集模型选择开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytor…

Unity中Shader序列图动画(UV流动的通用起始点)

文章目录 前言一、一般序列帧动画是按照序列图如下顺序读取的二、在Shader找到UV流动的起始点1、先实现纹理采样2、得到 uv 走格的单位格子大小3、定位到左上角为起始单位格 三、使UV流动的起始点通用化1、在属性面板接收 行 和 列的属性2、看图片可以总结出第一个单元格的公式…

Kotlin/JS工程构建及编译运行到浏览器

概述 Kotlin/JS 提供了转换 Kotlin 代码、Kotlin 标准库的能力&#xff0c;并且兼容 JavaScript 的任何依赖项。Kotlin/JS 的当前实现以 ES5 为目标。 使用 Kotlin/JS 的推荐方法是通过 kotlin.multiplatform Gradle 插件。它提供了一种集中且便捷的方式来设置与控制以 JavaS…

华为DriveONE电机控制器拆解实拍

如果说之前的问界M5、M7&#xff0c;华为让我们看到其在智能化上确实拥有遥遥领先的能力&#xff0c;那么在智界S7上&#xff0c;则让我们看到华为在动力、底盘这些硬件执行层面&#xff0c;竟然也有不输给很多车企的实力。1、华为电驱&#xff0c;全球第一&#xff1f;在智界S…

8K超高清应用:输电线网智慧巡检提升巡视效率

电力安全关系国计民生&#xff0c;是国家安全的重要保障&#xff0c;因此确保电力线路系统的安全运行至关重要。电力线路系统整体分为三大板块&#xff1a;输电线路、变电站和配电线路。然而&#xff0c;由于自然灾害、人为破坏等因素影响&#xff0c;这三大板块的设备很容易发…

开启Hyper-V

开启Hyper-V 为了给windows-ltsc激活&#xff0c;只好给系统装个虚拟机服务器。VMware太大了&#xff0c;于是想起Hyper-V。 走起。 在搜索栏直接搜索“windows功能”就能找到“开启或关闭windows功能”&#xff0c;直接勾选Hyper-V&#xff0c;就能安装了。重启后&#xff0c;…

不同阶数的巴特沃斯低通滤波器的空间域表示——数字图像处理

原理 巴特沃斯低通滤波器&#xff08;Butterworth Low-Pass Filter&#xff09;在频率域中的定义是明确的&#xff0c;但它在空间域中的表示不是直观的。这是因为巴特沃斯滤波器的形式是基于频率的&#xff0c;并且其空间域表示涉及到一个复杂的逆傅里叶变换&#xff0c;该变换…

透明展示柜的安装方法

透明展示柜的安装方法主要包括以下步骤&#xff1a; 准备工具和材料&#xff1a;在安装前&#xff0c;需要准备相应的工具和材料&#xff0c;如螺丝刀、电钻、固定架、玻璃板、胶水等。 确定安装位置&#xff1a;选择一个合适的安装位置&#xff0c;确保展示柜的摆放位置合理&…

关于“Python”的核心知识点整理大全62

目录 20.2.2 安装 Heroku Toolbelt 20.2.3 安装必要的包 注意 20.2.4 创建包含包列表的文件 requirements.txt requirements.txt requirements.txt 注意 20.2.5 指定 Python 版本 runtime.txt 注意 20.2.6 为部署到 Herohu 而修改 settings.py settings.py 20.2.7…

SparkStreaming基础解析(四)

1、 Spark Streaming概述 1.1 Spark Streaming是什么 Spark Streaming用于流式数据的处理。Spark Streaming支持的数据输入源很多&#xff0c;例如&#xff1a;Kafka、Flume、Twitter、ZeroMQ和简单的TCP套接字等等。数据输入后可以用Spark的高度抽象原语如&#xff1a;map、…

鸿蒙南向开发—OpenHarmony技术编译构建框架

概述 OpenHarmony编译子系统是以GN和Ninja构建为基座&#xff0c;对构建和配置粒度进行部件化抽象、对内建模块进行功能增强、对业务模块进行功能扩展的系统&#xff0c;该系统提供以下基本功能&#xff1a; 以部件为最小粒度拼装产品和独立编译。支持轻量、小型、标准三种系…

竞赛保研 基于机器视觉的行人口罩佩戴检测

简介 2020新冠爆发以来&#xff0c;疫情牵动着全国人民的心&#xff0c;一线医护工作者在最前线抗击疫情的同时&#xff0c;我们也可以看到很多科技行业和人工智能领域的从业者&#xff0c;也在贡献着他们的力量。近些天来&#xff0c;旷视、商汤、海康、百度都多家科技公司研…

思科常用图标大全Cisco产品图标库Icon(附PPT下载)

华为企业网络常用图标大全&#xff08;附PPT下载&#xff09;-CSDN博客文章浏览阅读2.8k次。PPT完整版获取交换机&WLAN服务器网络&网管建筑公共终端end_华为企业网络常用图标大全https://blog.csdn.net/XMWS_IT/article/details/120864637?ops_request_misc%257B%2522…

OpenAI ChatGPT-4开发笔记2024-03:Chat之Function Calling/Function/Tool/Tool_Choice

Updates on Function Calling were a major highlight at OpenAI DevDay. In another world,原来的function call都不再正常工作了&#xff0c;必须全部重写。 function和function call全部由tool和tool_choice取代。2023年11月之前关于function call的代码都准备翘翘。 干嘛…

【Java EE初阶八】多线程案例(计时器模型)

1. java标准库的计时器 1.1 关于计时器 计时器类似闹钟&#xff0c;有定时的功能&#xff0c;其主要是到时间就会执行某一操作&#xff0c;即可以指定时间&#xff0c;去执行某一逻辑&#xff08;某一代码&#xff09;。 1.2 计时器的简单介绍 在java标准库中&#xff0c;提供…

新手可理解的PyTorch线性层解析:神经网络的构建基石

目录 torch.nn子模块Linear Layers详解 nn.Identity Identity 类描述 Identity 类的功能和作用 Identity 类的参数 形状 示例代码 nn.Linear Linear 类描述 Linear 类的功能和作用 Linear 类的参数 形状 变量 示例代码 nn.Bilinear Bilinear 类的功能和作用 B…