Skip to content

Latest commit

 

History

History
460 lines (356 loc) · 12.9 KB

java_signature_demo.md

File metadata and controls

460 lines (356 loc) · 12.9 KB
  • JAVA signature - ApiSignature.java
package com.test.huobi;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;


public class ApiSignature {

  public static final String op = "op";
  public static final String opValue = "auth";
  private static final String accessKeyId = "AccessKeyId";
  private static final String signatureMethod = "SignatureMethod";
  private static final String signatureMethodValue = "HmacSHA256";
  private static final String signatureVersion = "SignatureVersion";
  private static final String signatureVersionValue = "2";
  private static final String timestamp = "Timestamp";
  private static final String signature = "Signature";

  private static final DateTimeFormatter DT_FORMAT = DateTimeFormatter
      .ofPattern("uuuu-MM-dd'T'HH:mm:ss");
  private static final ZoneId ZONE_GMT = ZoneId.of("Z");


  public void createSignature(String accessKey, String secretKey, String method, String host,
      String uri, UrlParamsBuilder builder) {
    StringBuilder sb = new StringBuilder(1024);

    if (accessKey == null || "".equals(accessKey) || secretKey == null || "".equals(secretKey)) {
      throw new HuobiApiException(HuobiApiException.KEY_MISSING,
          "API key and secret key are required");
    }

    sb.append(method.toUpperCase()).append('\n')
        .append(host.toLowerCase()).append('\n')
        .append(uri).append('\n');

    builder.putToUrl(accessKeyId, accessKey)
        .putToUrl(signatureVersion, signatureVersionValue)
        .putToUrl(signatureMethod, signatureMethodValue)
        .putToUrl(timestamp, gmtNow());

    sb.append(builder.buildSignature());
    Mac hmacSha256;
    try {
      hmacSha256 = Mac.getInstance(signatureMethodValue);
      SecretKeySpec secKey = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8),
          signatureMethodValue);
      hmacSha256.init(secKey);
    } catch (NoSuchAlgorithmException e) {
      throw new HuobiApiException(HuobiApiException.RUNTIME_ERROR,
          "[Signature] No such algorithm: " + e.getMessage());
    } catch (InvalidKeyException e) {
      throw new HuobiApiException(HuobiApiException.RUNTIME_ERROR,
          "[Signature] Invalid key: " + e.getMessage());
    }
    String payload = sb.toString();
    byte[] hash = hmacSha256.doFinal(payload.getBytes(StandardCharsets.UTF_8));

    String actualSign = Base64.getEncoder().encodeToString(hash);

    builder.putToUrl(signature, actualSign);

  }

  private static long epochNow() {
    return Instant.now().getEpochSecond();
  }

  static String gmtNow() {
    return Instant.ofEpochSecond(epochNow()).atZone(ZONE_GMT).format(DT_FORMAT);
  }
}

-UrlParamsBuilder.class

package com.test.huobi;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import com.alibaba.fastjson.JSON;
import okhttp3.MediaType;
import okhttp3.RequestBody;


public class UrlParamsBuilder {

  class ParamsMap {

    final Map<String, String> map = new HashMap<>();
    final Map<String, List> stringListMap = new HashMap<>();

    void put(String name, String value) {

      if (name == null || "".equals(name)) {
        throw new HuobiApiException(HuobiApiException.RUNTIME_ERROR,
            "[URL] Key can not be null");
      }
      if (value == null || "".equals(value)) {
        return;
      }

      map.put(name, value);
    }

    void put(String name, Integer value) {
      put(name, value != null ? Integer.toString(value) : null);
    }

    void put(String name, Date value, String format) {
      SimpleDateFormat dateFormatter = new SimpleDateFormat(format);
      put(name, value != null ? dateFormatter.format(value) : null);
    }

    void put(String name, Long value) {
      put(name, value != null ? Long.toString(value) : null);
    }

    void put(String name, BigDecimal value) {
      put(name, value != null ? value.toPlainString() : null);
    }

  }

  private static final MediaType JSON_TYPE = MediaType.parse("application/json");
  private final ParamsMap paramsMap = new ParamsMap();
  private final ParamsMap postBodyMap = new ParamsMap();
  private boolean postMode = false;

  public static UrlParamsBuilder build() {
    return new UrlParamsBuilder();
  }

  private UrlParamsBuilder() {
  }

  public UrlParamsBuilder setPostMode(boolean mode) {
    postMode = mode;
    return this;
  }

  public <T extends Enum> UrlParamsBuilder putToUrl(String name, T value) {
    if (value != null) {
      paramsMap.put(name, value.toString());
    }
    return this;
  }

  public UrlParamsBuilder putToUrl(String name, String value) {
    paramsMap.put(name, value);
    return this;
  }

  public UrlParamsBuilder putToUrl(String name, Date value, String format) {
    paramsMap.put(name, value, format);
    return this;
  }

  public UrlParamsBuilder putToUrl(String name, Integer value) {
    paramsMap.put(name, value);
    return this;
  }

  public UrlParamsBuilder putToUrl(String name, Long value) {
    paramsMap.put(name, value);
    return this;
  }

  public UrlParamsBuilder putToUrl(String name, BigDecimal value) {
    paramsMap.put(name, value);
    return this;
  }

  public UrlParamsBuilder putToPost(String name, String value) {
    postBodyMap.put(name, value);
    return this;
  }

  public <T extends Enum> UrlParamsBuilder putToPost(String name, T value) {
    if (value != null) {
      postBodyMap.put(name, value.toString());
    }
    return this;
  }

  public UrlParamsBuilder putToPost(String name, Date value, String format) {
    postBodyMap.put(name, value, format);
    return this;
  }

  public UrlParamsBuilder putToPost(String name, Integer value) {
    postBodyMap.put(name, value);
    return this;
  }

  public <T> UrlParamsBuilder putToPost(String name, List<String> list) {
    postBodyMap.stringListMap.put(name, list);
    return this;
  }

  public UrlParamsBuilder putToPost(String name, Long value) {
    postBodyMap.put(name, value);
    return this;
  }

  public UrlParamsBuilder putToPost(String name, BigDecimal value) {
    postBodyMap.put(name, value);
    return this;
  }

  public String buildUrl() {
    Map<String, String> map = new HashMap<>(paramsMap.map);
    StringBuilder head = new StringBuilder("?");
    return AppendUrl(map, head);

  }

  public String buildSignature() {
    Map<String, String> map = new TreeMap<>(paramsMap.map);
    StringBuilder head = new StringBuilder();
    return AppendUrl(map, head);

  }

  private String AppendUrl(Map<String, String> map, StringBuilder stringBuilder) {
    for (Map.Entry<String, String> entry : map.entrySet()) {
      if (!("").equals(stringBuilder.toString())) {
        stringBuilder.append("&");
      }
      stringBuilder.append(entry.getKey());
      stringBuilder.append("=");
      stringBuilder.append(urlEncode(entry.getValue()));
    }
    return stringBuilder.toString();
  }

  public RequestBody buildPostBody() {
    if (postBodyMap.stringListMap.isEmpty()) {
      if (postBodyMap.map.isEmpty()) {
        return RequestBody.create(JSON_TYPE, "");
      } else {
        return RequestBody.create(JSON_TYPE, JSON.toJSONString(postBodyMap.map));
      }
    } else {
      return RequestBody.create(JSON_TYPE, JSON.toJSONString(postBodyMap.stringListMap));


    }
  }

  public boolean hasPostParam() {
    return !postBodyMap.map.isEmpty() || postMode;
  }


  public String buildUrlToJsonString() {
    return JSON.toJSONString(paramsMap.map);
  }

  /**
   * 使用标准URL Encode编码。注意和JDK默认的不同,空格被编码为%20而不是+。
   *
   * @param s String字符串
   * @return URL编码后的字符串
   */
  private static String urlEncode(String s) {
    try {
      return URLEncoder.encode(s, "UTF-8").replaceAll("\\+", "%20");
    } catch (UnsupportedEncodingException e) {
      throw new HuobiApiException(HuobiApiException.RUNTIME_ERROR,
          "[URL] UTF-8 encoding not supported!");
    }
  }
}
  • HuobiApiException.java
package com.test.huobi;

public class HuobiApiException extends RuntimeException {


  public static final String RUNTIME_ERROR = "RuntimeError";
  public static final String INPUT_ERROR = "InputError";
  public static final String KEY_MISSING = "KeyMissing";
  public static final String SYS_ERROR = "SysError";
  public static final String SUBSCRIPTION_ERROR = "SubscriptionError";
  public static final String ENV_ERROR = "EnvironmentError";
  public static final String EXEC_ERROR = "ExecuteError";
  private final String errCode;

  public HuobiApiException(String errType, String errMsg) {
    super(errMsg);
    this.errCode = errType;
  }

  public HuobiApiException(String errType, String errMsg, Throwable e) {
    super(errMsg, e);
    this.errCode = errType;
  }

  public String getErrType() {
    return this.errCode;
  }
}
  • JAVA demo - HuobiSignatureDemo.java
package com.test.huobi;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class HuobiSignatureDemo {

  static final String HOST = "https://api.huobi.vn";
  static OkHttpClient okHttpClient = new OkHttpClient();
  static final String API_KEY = "api key";
  static final String SECRET_KEY = "secret key";
  static final Long SPOT_ACCOUNT_ID =123456L;

  public static void main(String[] args) {

    String clientOrderId = "TT" + System.nanoTime();
    String symbol = "htusdt";

    // 创建订单
    Long orderId = createOrder(SPOT_ACCOUNT_ID, clientOrderId, symbol, "buy-limit", new BigDecimal("2"), new BigDecimal("1"));

    // 查询订单
    getOrderByClientOrderId(clientOrderId);

    // 撤销订单
    submitCancelClientOrder(clientOrderId);


  }

  public static Long createOrder(Long accountId, String clientOrderId, String symbol, String type, BigDecimal price, BigDecimal amount) {

    String path = "/v1/order/orders/place";

    UrlParamsBuilder builder = UrlParamsBuilder.build()
        .putToPost("account-id", accountId)
        .putToPost("amount", amount)
        .putToPost("price", price)
        .putToPost("symbol", symbol)
        .putToPost("type", type)
        .putToPost("client-order-id", clientOrderId)
        .putToPost("source", "spot-api");

    new ApiSignature().createSignature(API_KEY, SECRET_KEY, "POST", getHost(), path, builder);

    String requestUrl = HOST + path + builder.buildUrl();
    Request executeRequest = new Request.Builder().url(requestUrl).post(builder.buildPostBody())
        .addHeader("Content-Type", "application/json").build();

    String response = execute(executeRequest);
    System.out.println(response);
    JSONObject jsonObject = JSON.parseObject(response);
    return jsonObject.getLong("data");
  }

  public static void getOrderByClientOrderId(String clientOrderId) {
    String path = "/v1/order/orders/getClientOrder";

    UrlParamsBuilder builder = UrlParamsBuilder.build()
        .putToUrl("clientOrderId", clientOrderId);

    new ApiSignature().createSignature(API_KEY, SECRET_KEY, "GET", getHost(), path, builder);

    String requestUrl = HOST + path + builder.buildUrl();

    Request executeRequest = new Request.Builder().url(requestUrl)
        .addHeader("Content-Type", "application/x-www-form-urlencoded").build();

    String response = execute(executeRequest);
    System.out.println(response);
  }

  public static void submitCancelClientOrder(String clientOrderId) {
    String path = "/v1/order/orders/submitCancelClientOrder";

    UrlParamsBuilder builder = UrlParamsBuilder.build()
        .putToPost("client-order-id", clientOrderId);

    new ApiSignature().createSignature(API_KEY, SECRET_KEY, "POST", getHost(), path, builder);

    String requestUrl = HOST + path + builder.buildUrl();
    Request executeRequest = new Request.Builder().url(requestUrl).post(builder.buildPostBody())
        .addHeader("Content-Type", "application/json").build();

    String response = execute(executeRequest);
    System.out.println(response);
  }

  public static String getHost() {
    try {
      URL url = new URL(HOST);
      return url.getHost();
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    return null;
  }

  public static String execute(Request executeRequest) {
    Response response = null;
    String str = null;
    try {
      response = okHttpClient.newCall(executeRequest).execute();
      if (response.code() == 200) {
        str = response.body().string();
      } else {
        str = response.toString();
      }

    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (response != null) {
        response.close();
      }
    }
    return str;
  }
}