通过 TBA 连接到 NetSuite 的问题

Issues Connecting to NetSuite Via TBA

我们正在将 SSO 集成转换为 TBA(相对于用户名和密码)。自从最近的 2016.2 升级以来,java 代码完全无法工作(注意,这在升级前确实有效)。当前的问题是我们收到 403 或错误的时间戳错误。使用 NetSutie,我没有发现这些变化何时发生的任何相关性。

我远不是 Java 专家,所以我希望这里有人可以提供帮助并告诉我这段代码有什么问题(我能够使用 NetSuite PHP 工具包,虽然)。

下面是我正在尝试的基本代码(大部分是从我们的 Java 开发人员那里收到的,我正在尝试为他们修复此问题),我自己使用 NetSuite 的想法进行了一些微调。

public class Main{
public static void main(String[]args){
    String compID="compID";
    String consumerKey="consumerKey";
    String consumerSecret="consumerSecret";
    String tokenId="tokenId";
    String tokenSecret="tokenSecret";
    String restletURL="https://rest.sandbox.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=2";

    Token token=new Token(tokenId,tokenSecret);
    String nonce=RandomStringUtils.randomNumeric(9);
    long ms=new java.util.Date().getTime();
    ms=(long)Math.floor(ms/1000);
    String time=ms+"";

    String baseString=compID+"&"+consumerKey+"&"+tokenId+"&"+nonce+"&"+time;
    String key=consumerSecret+"&"+tokenSecret;
    byte[] bytes=key.getBytes();
    SecretKeySpec secretkey=new SecretKeySpec(bytes,"HmacSHA1");
    Mac keymac=null;
    try{
        keymac=Mac.getInstance("HmacSHA1");
        keymac.init(secretkey);
    }catch(NoSuchAlgorithmException e){
        e.printStackTrace();
    }catch(InvalidKeyException e){
        e.printStackTrace();
    }
    byte[] hash=keymac.doFinal(baseString.getBytes());
    String result=new String(Base64.encodeBase64(hash,false));
    String oauth_timestamp = Instant.now().toEpochMilli()+"";

    String headerAuthorization="OAuth realm=\""+compID+"\", oauth_consumer_key=\""+consumerKey+"\", oauth_token=\""+token+"\", oauth_nonce=\""+nonce+"\", oauth_timestamp=\""+oauth_timestamp+"\", oauth_signature_method=\"HMAC-SHA1\", oauth_version=\"1.0\", oauth_signature=\""+result+"\"";

    System.out.println(headerAuthorization);

    HttpClient httpclient=HttpClientBuilder.create().build();

    HttpGet request=new HttpGet(restletURL);
    request.setHeader(HttpHeaders.AUTHORIZATION,headerAuthorization);

    String response="";
    try{
        //Handle the response from NetSuite
        ResponseHandler<String> responseHandler=new ResponseHandler<String>(){
            @Override
            public String handleResponse(final HttpResponse response)throws ClientProtocolException,IOException{
                int status=response.getStatusLine().getStatusCode();

                //If the call is successful
                if(status>=200 && status<300){
                    HttpEntity entity=response.getEntity();
                    return entity!=null?EntityUtils.toString(entity):null;
                }else{
                    throw new ClientProtocolException("Unexpected response status: "+status);
                }
            }
        };
        response=httpclient.execute(request,responseHandler);
        System.out.println(response);
    }catch(Exception e){
        e.printStackTrace();
    }
  }
}

我们终于成功了。事实证明,在 NetSuite 中改变了他们 API 的工作方式(至少根据他们告诉我的)。要获得此 运行,需要 Scribe 1.3.7 (Maven Repo)。那么你需要两个 Java 文件如下所述:

DummyService.java

import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;

public class DummyService extends DefaultApi10a{
  @Override
  public String getAccessTokenEndpoint() {
    // TODO Auto-generated method stub
    return null;
  }
  @Override
  public String getAuthorizationUrl(Token arg0) {
    // TODO Auto-generated method stub
    return null;
  }
  @Override
  public String getRequestTokenEndpoint() {
    // TODO Auto-generated method stub
    return null;
  }
}

TokenAuth.java

import org.scribe.builder.ServiceBuilder;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.SignatureType;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.oauth.OAuthService;

public class TokenAuth{
  private static final String TOKEN_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  private static final String TOKEN_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  private static final String CONSUMER_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  private static final String CONSUMER_SECRET="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  private static final String REALM="123456";
  private static final String CONTENT_TYPE="content-type";
  private static final String APP_JSON="application/json";

  private static final String REST_URL="https://rest.sandbox.netsuite.com/app/site/hosting/restlet.nl?script=xxx&deploy=x";
  private static final String JSON_PAYLOD="{}";

  private static OAuthService service=getService();
  private static Token accessToken=getToken();
  public static void main(String[]args){
    Response responseGet=callWithHttpGet();
    System.out.println(responseGet.getBody());  
    Response responsePost=callWithHttpPost();
    System.out.println(responsePost.getBody());
  }
  private static Response callWithHttpGet(){
    OAuthRequest request=new OAuthRequest(Verb.GET,REST_URL);
    request.setRealm(REALM);
    service.signRequest(accessToken,request);
    return request.send();
  }
  private static Response callWithHttpPost(){
    OAuthRequest request=new OAuthRequest(Verb.POST,REST_URL);
    request.setRealm(REALM);
    request.addHeader(CONTENT_TYPE,APP_JSON);
    request.addPayload(JSON_PAYLOD);
    service.signRequest(accessToken,request);
    return request.send();
  }
  private static Token getToken(){
    return new Token(TOKEN_ID, TOKEN_SECRET);
  }
  private static OAuthService getService(){
    return new ServiceBuilder().provider(DummyService.class).apiKey(CONSUMER_KEY).apiSecret(CONSUMER_SECRET).signatureType(SignatureType.Header).build();
  }
}

*注意: SuiteAnswers 文章中的数据现已更新(除了 Scribe 1.3.7 的要求),以及 (42167 - Java > RESTlet Authentication using Token (Token-Based Authentication))