Java TBA访问NetSuite Restlet时的403错误

发布时间:2024年01月05日

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

文章来源:https://blog.csdn.net/remottshanghai/article/details/135400167
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。