Java TBA访问NetSuite Restlet时的403错误

news2025/1/18 20:32:21

本周有同学问为啥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-5


import 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 nonce
    private 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 debugging
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .addInterceptor(loggingInterceptor)
                .build();

        // Create the request URL
        HttpUrl requestUrl = HttpUrl.parse("https://" + NETSUITE_ACCOUNT + ".restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=1795&deploy=1");

        // Generate the Authorization header value
        String authorizationHeader = generateAuthorizationHeader(requestUrl.toString());

        // Create the request
        Request request = new Request.Builder()
                .url(requestUrl)
                .header("Authorization", authorizationHeader)
                .get()
                .build();

        // Execute the request
        try (Response response = httpClient.newCall(request).execute()) {
            // Process the response
            String responseBody = response.body().string();
            System.out.println(responseBody);
        }
    }

    private static String generateAuthorizationHeader(String url) throws Exception {

        String baseString = baseStringConcat();

        // Generate the signature
        String signature = generateSignature(baseString, NETSUITE_CONSUMER_SECRET, NETSUITE_TOKEN_SECRET);


        // Construct the Authorization header value
        String 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 URL
        String encodedUrl = URLEncoder.encode(url, StandardCharsets.UTF_8);

        // Sort and encode the parameters
        Map<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 '&' character
        if (baseString.length() > 0) {
            baseString.setLength(baseString.length() - 1);
        }

        // Construct the signature base string
        String 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.coloradmin.cn/o/1357858.html

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

相关文章

云原生战专题 | 深入浅出分析云原生微服务的技术结构和架构设计

深入浅出分析云原生微服务的技术结构和架构设计 云原生容器技术背景容器编排Kubernetes控制平面的四大组件Kubernetes在容器编排中的设计要点 云原生微服务典型架构第一代微服务架构第二代微服务架构第三代微服务架构第四代微服务架构 未来的云原生架构 — Serverless 云原生容…

mysql 添加用户并分配select权限

1.root用户先登录或者在可执行界面 1.1 选择mysql 点击mysql 或者在命令行 use mysql 1.2创建用户 CREATE USER username% IDENTIFIED BY password; 备注1&#xff1a;%替换为可访问数据库的ip&#xff0c;例如“127.0.0.1”“192.168.1.1”&#xff0c;使用“%”表示不限制…

2.HDFS 架构

目录 概述架构HDFS副本HDFS数据写入流程NN 工作原理DN 工作原理 结束 概述 官方文档快递 环境&#xff1a;hadoop 版本 3.3.6 相关文章速递 架构 HDFS HDFS 架构总结如下&#xff1a; a master/slave architecture 一主多从架构a file is split into one or more blocks a…

【python高级用法】进程

一个简单的进程 # -*- coding: utf-8 -*-import multiprocessingdef foo(i):print (called function in process: %s %i)returnif __name__ __main__:Process_jobs []for i in range(5):p multiprocessing.Process(targetfoo, args(i,))Process_jobs.append(p)p.start()p.j…

展望2024: 中国AI算力能否引爆高性能计算和大模型训练的新革命?

★算力&#xff1b;算法&#xff1b;人工智能&#xff1b;高性能计算&#xff1b;高性能&#xff1b;高互联&#xff1b;生成式人工智能&#xff1b;StableDiffusion&#xff1b;ChatGPT&#xff1b;CoPilot&#xff1b;文本创建&#xff1b;图像生成&#xff1b;代码编写&…

Transformer从菜鸟到新手(三)

引言 这是Transformer的第三篇文章&#xff0c;上篇文章中我们了解了多头注意力和位置编码&#xff0c;本文我们继续了解Transformer中剩下的其他组件。 层归一化 层归一化想要解决一个问题&#xff0c;这个问题在Batch Normalization的论文中有详细的描述&#xff0c;即深层…

Windows找不到文件‘chrome‘,请确定文件名是否正确后,再试一次。

本文主要记录遇到vscode运行HTML文件提示&#xff1a; Windows找不到文件‘chrome‘&#xff0c;请确定文件名是否正确后&#xff0c;再试一次。问题的解决办法。 目录 一、打开设置 二 、搜索Live Server Config &#xff08;1&#xff09;安装Live Server插件 &#xff0…

弧垂观测手段再升级!输电线路导线弧垂检测装置的应用_深圳鼎信

输电线路导线弧垂是指在输电线路中导线的水平位置与塔杆之间的垂直距离。导线的弧垂是确定导线张力、塔杆高度等参数的重要依据。通过测量弧垂及时调整弧垂大小对保证输电线路的安全运行具有重要作用。鼎信将介绍两种测量弧垂的方法&#xff0c;一起来学习一下吧&#xff01; …

TikTok明星经济:短视频背后的网络名人

在当今数字时代&#xff0c;社交媒体平台的崛起为许多人带来了独特的机遇&#xff0c;其中TikTok作为一款短视频应用&#xff0c;正成为网络名人崛起的孵化器。随着TikTok用户量的不断增加&#xff0c;平台上涌现出越来越多的明星&#xff0c;这些明星不仅仅在虚拟世界中受到欢…

微信小程序分销商城制作源码系统:全部搭建好直接使用 带完整的安装代码包以及搭建教程

随着移动设备的普及和互联网技术的发展&#xff0c;电子商务逐渐成为人们购物的主要方式之一。而微信作为中国最大的社交平台之一&#xff0c;拥有庞大的用户基数和成熟的生态系统。因此&#xff0c;基于微信小程序开发分销商城具有巨大的市场潜力和商业价值。 以下是部分代码…

超级详细的 https 中间人攻击流程。

客户端发送 https 请求中间人截获 https 请求&#xff0c;然后在转发给服务端 中间人可以是抓包工具中间人可以通过伪造证书的方式截获请求服务端接收到请求【看起来是客户端发的&#xff0c;实际上已经经过中间人转发了】服务端以为是一个安全的请求&#xff0c;向客户端发送数…

计算机研究生论文检索方法汇总

计算机研究生论文检索方法汇总 作为一名优质(冤种)计算机在读研究生&#xff0c;检索论文是一项不可或缺的技能之一。 一、paperwithcode paperswithcode是一个免费开放的资源平台&#xff0c;提供了机器学习领域的论文、代码、数据集、方法和评估表。在这里我们可以检索不同…

对图片进行数据增强(基于pytorch)

背景 在进行机器学习的任务中&#xff0c;我们的训练数据往往是有限的&#xff0c;在有限的数据集上获得较好的模型训练结果&#xff0c;我们不仅要在模型结构上下功夫&#xff0c;另一方面也需要对数据集进行数据增强 图片数据增强 图像数据增强是一种在训练机器学习和深度学…

设计模式② :交给子类

文章目录 一、前言二、Template Method 模式1. 介绍2. 应用3. 总结 三、Factory Method 模式1. 介绍2. 应用3. 总结 参考内容 一、前言 有时候不想动脑子&#xff0c;就懒得看源码又不像浪费时间所以会看看书&#xff0c;但是又记不住&#xff0c;所以决定开始写"抄书&qu…

脑电范式学习(一):Psychopy安装

脑电范式学习&#xff08;一&#xff09;&#xff1a;Psychopy安装 1 引言2 Psychopy软件3 安装教程4 花活儿5 总结 1 引言 可能有人会疑惑&#xff1a;为什么要去学Psychopy&#xff1f;Psychopy有什么好的&#xff1f; 首先&#xff0c;要告诉大家这么一个情况&#xff1a;现…

使用 Swagger 导入 Postman: 最佳实践与步骤解析

Swagger和 Postman 都是常用的 API 测试工具&#xff0c;都有各自的优势。为了结合两者的优点&#xff0c;我们可以考虑将 Swagger 中的 API 定义导入到 Postman 中去&#xff0c;这样就可以利用 Postman 更强大的测试功能来测试 Swagger 定义的接口。 下面将以 Swagger Petst…

Spark调优解析-spark调优基本原则1(七)

1调优基本原则 1.1基本概念和原则 首先&#xff0c;要搞清楚Spark的几个基本概念和原则&#xff0c;否则系统的性能调优无从谈起&#xff1a; 每一台host上面可以并行N个worker&#xff0c;每一个worker下面可以并行M个executor&#xff0c;task们会被分配到executor上面去执…

yolov8实战第五天——yolov8+ffmpg实时视频流检测并进行实时推流——(推流,保姆教学)

yolov8实战第一天——yolov8部署并训练自己的数据集&#xff08;保姆式教程&#xff09;_yolov8训练自己的数据集-CSDN博客 yolov8实战第三天——yolov8TensorRT部署&#xff08;python推理&#xff09;&#xff08;保姆教学&#xff09;-CSDN博客 今天&#xff0c;我们继续y…

大数据开发个人简历范本(2024最新版-附模板)

大数据开发工程师个人简历范本> 男 22 本科 张三 计算机科学与技术 1234567890 个人概述 具备深入的Hadoop大数据运维工程师背景&#xff0c;熟悉相关技术和工具 具备良好的团队合作能力&#xff0c;善于沟通和协作 具有快速学习新知识和解决问题的能力 对于数据科学…

模型 回弹效应

系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。行动反弹&#xff0c;效果加倍。 1 回弹效应的应用 1.1 纽约市的经济复苏-经济发展中的回弹效应 在20世纪70年代和80年代&#xff0c;纽约市面临了经济衰退、高犯罪率和城市衰败等问题。这导…