百度智能云鉴权Demo示例
更新时间:2024-09-20
百度智能云鉴权Demo示例
说明: 在面临复杂的工程环境中经常出现依赖版本冲突,故提供无必要外部依赖的代码示例。 注:百度智能云兼容AWS的鉴权方式,本示例也进行提供,请按需接入获取。
本文档整理了在JAVA中常见的http工具,具体选取以实际工程选其一即可,另文档中只有执行示例。详细请参考鉴权认证机制
以下为当前示例运行环境,实际使用可自行调整:
环境 | 版本 |
---|---|
JDK | 1.8 |
Maven | 3.9.x |
Okhttp3 | 4.12.0 |
Apache Httpclient | 4.5.13 |
说明: 注意:核心代码中的ak/sk需替换为百度智能云账号下的ak/sk管理您的AKSK,以及具体的业务接口。点击下载完整示例代码
OkHttp3示例(推荐)
Maven依赖
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
baiduV1版本(推荐)
核心代码
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
public class BaiduV1Singer {
!!! todo 修改成自己的ak和sk
private static final String ACCESS_KEY = "your_ak";
private static final String SECRET_KEY = "your_sk";
public static final String HOST = "Host";
public static final String AUTHORIZATION = "Authorization";
public static final String CONTENT_LENGTH = "Content-Length";
public static final String CONTENT_MD5 = "Content-MD5";
public static final String CONTENT_TYPE = "Content-Type";
public static final String BCE_PREFIX = "x-bce-";
private static final String BCE_AUTH_VERSION = "bce-auth-v1";
private static final String DEFAULT_ENCODING = "UTF-8";
private static final Charset UTF8 = Charset.forName(DEFAULT_ENCODING);
private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet();
private static final String[] PERCENT_ENCODED_STRINGS = new String[256];
private static final Set<String> defaultHeadersToSign = new HashSet<>();
private static final java.time.format.DateTimeFormatter formatter =
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
defaultHeadersToSign.add(HOST.toLowerCase());
defaultHeadersToSign.add(CONTENT_LENGTH.toLowerCase());
defaultHeadersToSign.add(CONTENT_TYPE.toLowerCase());
defaultHeadersToSign.add(CONTENT_MD5.toLowerCase());
}
static {
for (int i = 'a'; i <= 'z'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
for (int i = 'A'; i <= 'Z'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
for (int i = '0'; i <= '9'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
URI_UNRESERVED_CHARACTERS.set('-');
URI_UNRESERVED_CHARACTERS.set('.');
URI_UNRESERVED_CHARACTERS.set('_');
URI_UNRESERVED_CHARACTERS.set('~');
for (int i = 0; i < PERCENT_ENCODED_STRINGS.length; ++i) {
PERCENT_ENCODED_STRINGS[i] = String.format("%%%02X", i);
}
}
public static String sign(String uri, String method, Map<String, String> parameters, Map<String, String> headers) {
String authString =
BCE_AUTH_VERSION + "/" + ACCESS_KEY + "/"
+ LocalDateTime.now(ZoneId.of("UTC")).format(formatter) + "/" + 1800;
String signingKey = sha256Hex(SECRET_KEY, authString);
String canonicalURI = getCanonicalURIPath(uri);
String canonicalQueryString = getCanonicalQueryString(parameters, true);
SortedMap<String, String> headersToSign = getHeadersToSign(headers, null);
String canonicalHeader = getCanonicalHeaders(headersToSign);
String signedHeaders;
signedHeaders = String.join(";", headersToSign.keySet());
signedHeaders = signedHeaders.trim().toLowerCase();
String canonicalRequest =
method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeader;
System.out.println("authString :" + authString);
System.out.println("signingKey :" + signingKey);
System.out.println("canonicalRequest: " + canonicalRequest);
// Signing the canonical request using key with sha-256 algorithm.
String signature = sha256Hex(signingKey, canonicalRequest);
return authString + "/" + signedHeaders + "/" + signature;
}
private static String sha256Hex(String signingKey, String stringToSign) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(signingKey.getBytes(UTF8), "HmacSHA256"));
return bytesToHex(mac.doFinal(stringToSign.getBytes(UTF8)));
} catch (Exception e) {
throw new RuntimeException("Fail to generate the signature", e);
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
private static String getCanonicalURIPath(String path) {
if (path == null) {
return "/";
} else if (path.startsWith("/")) {
return normalizePath(path);
} else {
return "/" + normalizePath(path);
}
}
private static String normalize(String value) {
try {
StringBuilder builder = new StringBuilder();
for (byte b : value.getBytes(DEFAULT_ENCODING)) {
if (URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) {
builder.append((char) b);
} else {
builder.append(PERCENT_ENCODED_STRINGS[b & 0xFF]);
}
}
return builder.toString();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private static String normalizePath(String path) {
return normalize(path).replace("%2F", "/");
}
private static String getCanonicalQueryString(Map<String, String> parameters, boolean forSignature) {
if (parameters.isEmpty()) {
return "";
}
List<String> parameterStrings = new ArrayList<>();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
if (forSignature && AUTHORIZATION.equalsIgnoreCase(entry.getKey())) {
continue;
}
String key = entry.getKey();
checkNotNull(key, "parameter key should not be null");
String value = entry.getValue();
if (value == null) {
if (forSignature) {
parameterStrings.add(normalize(key) + '=');
} else {
parameterStrings.add(normalize(key));
}
} else {
parameterStrings.add(normalize(key) + '=' + normalize(value));
}
}
Collections.sort(parameterStrings);
return String.join("&",parameterStrings);
}
private static <T> T checkNotNull(T reference, Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
} else {
return reference;
}
}
private static SortedMap<String, String> getHeadersToSign(Map<String, String> headers, Set<String> headersToSign) {
SortedMap<String, String> ret = new TreeMap<>();
if (headersToSign != null) {
Set<String> tempSet = new HashSet<>();
for (String header : headersToSign) {
tempSet.add(header.trim().toLowerCase());
}
headersToSign = tempSet;
}
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
if (entry.getValue() != null && !entry.getValue().isEmpty()) {
if ((headersToSign == null && isDefaultHeaderToSign(key))
|| (headersToSign != null && headersToSign.contains(key.toLowerCase())
&& !AUTHORIZATION.equalsIgnoreCase(key))) {
ret.put(key, entry.getValue());
}
}
}
return ret;
}
private static boolean isDefaultHeaderToSign(String header) {
header = header.trim().toLowerCase();
return header.startsWith(BCE_PREFIX) || defaultHeadersToSign.contains(header);
}
private static String getCanonicalHeaders(SortedMap<String, String> headers) {
if (headers.isEmpty()) {
return "";
}
List<String> headerStrings = new ArrayList<>();
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
if (key == null) {
continue;
}
String value = entry.getValue();
if (value == null) {
value = "";
}
headerStrings.add(normalize(key.trim().toLowerCase()) + ':' + normalize(value.trim()));
}
Collections.sort(headerStrings);
return String.join("\n", headerStrings);
}
}
测试代码
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.intellij.lang.annotations.Language;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import static com.baidu.duhome.BaiduV1Singer.sign;
import static com.sun.deploy.net.HttpRequest.CONTENT_TYPE;
public class BaiduV1SingerTest {
@Test
public void okhttpPostTest() throws Exception {
String host = "smarthome-bdvs.baidubce.com";
!!! 具体的业务接口
String uri = "/v1/dynamicDict/list";
String url = "https://" + host + uri;
!!! todo: 请求体
@Language("JSON") String requestBody = "{\n" +
" \"fc\": \"device_fc\",\n" +
" \"pk\": \"device_pk\",\n" +
" \"ak\": \"mock_ak02\",\n" +
" \"normValue\": \"A01\",\n" +
" \"synonymValue\": \"xxxx" +
"\"\n" +
"}";
Map<String, String> hashMap = new HashMap<>();
hashMap.put("Content-Type", "application/json");
hashMap.put("HOST", host);
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse(CONTENT_TYPE);
Request request = new Request.Builder()
.header("Content-Type", "application/json")
.header("Host", host)
.header("Authorization", sign(uri, "POST", new HashMap<>(), hashMap))
// 构建requestBody 不能使用字符的方法,可以使用字节数组或者流的方式,字符串的方法中会强制在请求头中增加 charaset=urf8; 导致鉴权失败
.post(RequestBody.create(requestBody.getBytes(StandardCharsets.UTF_8), mediaType))
.url(url)
.build();
try (Response execute = client.newCall(request).execute()) {
String string = null;
if (execute.body() != null) {
string = execute.body().string();
}
System.out.println(string);
}
}
@Test
public void okhttpGetTest() throws Exception {
String host = "smarthome-bdvs.baidubce.com";
String uri = "/v1/foo";
String url = "http://" + host + uri;
Map<String, String> hashMap = new HashMap<>();
hashMap.put("HOST", host);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.header("Host", host)
.header("Authorization", sign(uri, "GET", new HashMap<>(), hashMap))
.get()
.url(url)
.build();
try (Response execute = client.newCall(request).execute()) {
String string = null;
if (execute.body() != null) {
string = execute.body().string();
}
System.out.println(string);
}
}
}
AWS版本
核心代码
import okhttp3.Request;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class AwsOkhttp3Signer {
private static final String ACCESS_KEY = "your_ak";
private static final String SECRET_KEY = "your_sk";
private static final String CONTENT_TYPE = "application/json";
/**
* 固定值
*/
private static final String REGION = "us-east-1";
/**
* 固定值
*/
private static final String SERVICE = "execute-api";
/**
* 生成带有签名的请求
*
* @param request 需要签名的请求
* @param requestBody 请求体
* @return 带有签名的请求
* @throws Exception 签名过程中可能发生的异常
*/
public static Request getSignedRequest(Request request, String requestBody) throws Exception {
String format = getAuthDate();
String authorizationHeader = getAuthorizationHeader(request.url().toString(), request.method(), requestBody, format);
return request.newBuilder()
.addHeader("Content-Type", CONTENT_TYPE)
.addHeader("Authorization", authorizationHeader)
.addHeader("X-Amz-Content-Sha256", calculateSHA256(requestBody))
.addHeader("X-Amz-Date", format)
.build();
}
private static String getAuthDate() {
return LocalDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
}
public static String getAuthorizationHeader(String url, String method, String requestBody, String amzDate) throws Exception {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new Exception("Invalid URL: " + url);
}
String host = uri.getAuthority();
String canonicalUri = uri.getPath();
String canonicalQuerystring = uri.getQuery();
String contentHash = calculateSHA256(requestBody);
String canonicalHeaders = "content-type:" + CONTENT_TYPE + "\n" +
"host:" + host + "\n" +
"x-amz-content-sha256:" + contentHash + "\n" +
"x-amz-date:" + amzDate + "\n";
String signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
String canonicalRequest = method + "\n" + canonicalUri + "\n" + (canonicalQuerystring == null ? "" : canonicalQuerystring) + "\n" +
canonicalHeaders + "\n" + signedHeaders + "\n" + contentHash;
String credentialScope = amzDate.substring(0, 8) + "/" + REGION + "/" + SERVICE + "/aws4_request";
String stringToSign = "AWS4-HMAC-SHA256\n" + amzDate + "\n" + credentialScope + "\n" +
calculateSHA256(canonicalRequest);
byte[] signingKey = getSigningKey(amzDate.substring(0, 8));
String signature = calculateHMAC(stringToSign, signingKey);
return "AWS4-HMAC-SHA256 Credential=" + ACCESS_KEY + "/" + credentialScope + ", " +
"SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
}
private static String calculateSHA256(String text) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
private static byte[] getSigningKey(String dateStamp) throws Exception {
byte[] kSecret = ("AWS4" + SECRET_KEY).getBytes(StandardCharsets.UTF_8);
byte[] kDate = hmacSHA256(dateStamp, kSecret);
byte[] kRegion = hmacSHA256(REGION, kDate);
byte[] kService = hmacSHA256(SERVICE, kRegion);
return hmacSHA256("aws4_request", kService);
}
private static byte[] hmacSHA256(String data, byte[] key) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
mac.init(keySpec);
return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
}
private static String calculateHMAC(String data, byte[] key) throws Exception {
byte[] hmacData = hmacSHA256(data, key);
return bytesToHex(hmacData);
}
}
测试代码
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.nio.charset.StandardCharsets;
import static com.baidu.duhome.AwsOkhttp3Signer.getSignedRequest;
import static com.sun.deploy.net.HttpRequest.CONTENT_TYPE;
public class Okhhtp3SignerTest {
@org.junit.Test
public void postApiTest() throws Exception {
!!! 具体业务地址
String url = "http://smarthome-bdvs.baidubce.com/v1/dynamicDict/list";
!!! todo: 请求体
String requestBody = "{\n" +
" \"fc\": \"device_fc\",\n" +
" \"pk\": \"device_pk\",\n" +
" \"ak\": \"mock_ak01\",\n" +
" \"normValue\": \"A01\",\n" +
" \"synonymValue\": \"xxxx\"\n" +
"}";
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse(CONTENT_TYPE);
Request request = new Request.Builder()
// 构建requestBody 不能使用字符的方法,可以使用字节数组或者流的方式,字符串的方法中会强制在请求头中增加 charaset=urf8; 导致鉴权失败
.post(RequestBody.create(requestBody.getBytes(StandardCharsets.UTF_8), mediaType))
.url(url)
.build();
// (进行签名) 注意会生成一个新的Request对象。
request = getSignedRequest(request, requestBody);
try (Response execute = client.newCall(request).execute()) {
String string = null;
if (execute.body() != null) {
string = execute.body().string();
}
System.out.println(string);
}
}
}
ApacheHttpClient示例
Maven依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
baiduV1版本(推荐)
核心代码
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
public class BaiduV1Singer {
!!! todo 修改成自己的ak和sk
private static final String ACCESS_KEY = "your_ak";
private static final String SECRET_KEY = "your_sk";
public static final String HOST = "Host";
public static final String AUTHORIZATION = "Authorization";
public static final String CONTENT_LENGTH = "Content-Length";
public static final String CONTENT_MD5 = "Content-MD5";
public static final String CONTENT_TYPE = "Content-Type";
public static final String BCE_PREFIX = "x-bce-";
private static final String BCE_AUTH_VERSION = "bce-auth-v1";
private static final String DEFAULT_ENCODING = "UTF-8";
private static final Charset UTF8 = Charset.forName(DEFAULT_ENCODING);
private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet();
private static final String[] PERCENT_ENCODED_STRINGS = new String[256];
private static final Set<String> defaultHeadersToSign = new HashSet<>();
private static final java.time.format.DateTimeFormatter formatter =
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
defaultHeadersToSign.add(HOST.toLowerCase());
defaultHeadersToSign.add(CONTENT_LENGTH.toLowerCase());
defaultHeadersToSign.add(CONTENT_TYPE.toLowerCase());
defaultHeadersToSign.add(CONTENT_MD5.toLowerCase());
}
static {
for (int i = 'a'; i <= 'z'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
for (int i = 'A'; i <= 'Z'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
for (int i = '0'; i <= '9'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
URI_UNRESERVED_CHARACTERS.set('-');
URI_UNRESERVED_CHARACTERS.set('.');
URI_UNRESERVED_CHARACTERS.set('_');
URI_UNRESERVED_CHARACTERS.set('~');
for (int i = 0; i < PERCENT_ENCODED_STRINGS.length; ++i) {
PERCENT_ENCODED_STRINGS[i] = String.format("%%%02X", i);
}
}
public static String sign(String uri, String method, Map<String, String> parameters, Map<String, String> headers) {
String authString =
BCE_AUTH_VERSION + "/" + ACCESS_KEY + "/"
+ LocalDateTime.now(ZoneId.of("UTC")).format(formatter) + "/" + 1800;
String signingKey = sha256Hex(SECRET_KEY, authString);
String canonicalURI = getCanonicalURIPath(uri);
String canonicalQueryString = getCanonicalQueryString(parameters, true);
SortedMap<String, String> headersToSign = getHeadersToSign(headers, null);
String canonicalHeader = getCanonicalHeaders(headersToSign);
String signedHeaders;
signedHeaders = String.join(";", headersToSign.keySet());
signedHeaders = signedHeaders.trim().toLowerCase();
String canonicalRequest =
method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeader;
System.out.println("authString :" + authString);
System.out.println("signingKey :" + signingKey);
System.out.println("canonicalRequest: " + canonicalRequest);
// Signing the canonical request using key with sha-256 algorithm.
String signature = sha256Hex(signingKey, canonicalRequest);
return authString + "/" + signedHeaders + "/" + signature;
}
private static String sha256Hex(String signingKey, String stringToSign) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(signingKey.getBytes(UTF8), "HmacSHA256"));
return bytesToHex(mac.doFinal(stringToSign.getBytes(UTF8)));
} catch (Exception e) {
throw new RuntimeException("Fail to generate the signature", e);
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
private static String getCanonicalURIPath(String path) {
if (path == null) {
return "/";
} else if (path.startsWith("/")) {
return normalizePath(path);
} else {
return "/" + normalizePath(path);
}
}
private static String normalize(String value) {
try {
StringBuilder builder = new StringBuilder();
for (byte b : value.getBytes(DEFAULT_ENCODING)) {
if (URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) {
builder.append((char) b);
} else {
builder.append(PERCENT_ENCODED_STRINGS[b & 0xFF]);
}
}
return builder.toString();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private static String normalizePath(String path) {
return normalize(path).replace("%2F", "/");
}
private static String getCanonicalQueryString(Map<String, String> parameters, boolean forSignature) {
if (parameters.isEmpty()) {
return "";
}
List<String> parameterStrings = new ArrayList<>();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
if (forSignature && AUTHORIZATION.equalsIgnoreCase(entry.getKey())) {
continue;
}
String key = entry.getKey();
checkNotNull(key, "parameter key should not be null");
String value = entry.getValue();
if (value == null) {
if (forSignature) {
parameterStrings.add(normalize(key) + '=');
} else {
parameterStrings.add(normalize(key));
}
} else {
parameterStrings.add(normalize(key) + '=' + normalize(value));
}
}
Collections.sort(parameterStrings);
return String.join("&", parameterStrings);
}
private static <T> T checkNotNull(T reference, Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
} else {
return reference;
}
}
private static SortedMap<String, String> getHeadersToSign(Map<String, String> headers, Set<String> headersToSign) {
SortedMap<String, String> ret = new TreeMap<>();
if (headersToSign != null) {
Set<String> tempSet = new HashSet<>();
for (String header : headersToSign) {
tempSet.add(header.trim().toLowerCase());
}
headersToSign = tempSet;
}
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
if (entry.getValue() != null && !entry.getValue().isEmpty()) {
if ((headersToSign == null && isDefaultHeaderToSign(key))
|| (headersToSign != null && headersToSign.contains(key.toLowerCase())
&& !AUTHORIZATION.equalsIgnoreCase(key))) {
ret.put(key, entry.getValue());
}
}
}
return ret;
}
private static boolean isDefaultHeaderToSign(String header) {
header = header.trim().toLowerCase();
return header.startsWith(BCE_PREFIX) || defaultHeadersToSign.contains(header);
}
private static String getCanonicalHeaders(SortedMap<String, String> headers) {
if (headers.isEmpty()) {
return "";
}
List<String> headerStrings = new ArrayList<>();
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
if (key == null) {
continue;
}
String value = entry.getValue();
if (value == null) {
value = "";
}
headerStrings.add(normalize(key.trim().toLowerCase()) + ':' + normalize(value.trim()));
}
Collections.sort(headerStrings);
return String.join("\n", headerStrings);
}
}
测试代码
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class BaiduV1SingerTest {
private static final String CONTENT_TYPE = "application/json";
@Test
public void postApiDemo() {
String host = "smarthome-bdvs.baidubce.com";
String uri = "/v1/dynamicDict/list";
String url = "https://" + host + uri;
// todo: 请求体
String requestBodyStr = "{\n" +
" \"fc\": \"device_fc\",\n" +
" \"pk\": \"device_pk\",\n" +
" \"ak\": \"mock_ak02\",\n" +
" \"normValue\": \"A01\",\n" +
" \"synonymValue\": \"xxxx" +
"\"\n" +
"}";
Map<String, String> hashMap = new HashMap<>();
hashMap.put(HttpHeaders.CONTENT_TYPE, "application/json");
hashMap.put(HttpHeaders.HOST, host);
// 创建一个HttpClient对象
try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
// 创建一个HttpGet请求
HttpPost httpPost = new HttpPost(url);
System.out.println("Executing request " + httpPost.getRequestLine());
// 进行百度请求签名
// AwsApacheHttpClientSigner.getSignedRequest(httpPost, requestBodyStr);
httpPost.setEntity(new StringEntity(requestBodyStr));
httpPost.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
httpPost.addHeader(HttpHeaders.HOST, host);
httpPost.addHeader(HttpHeaders.AUTHORIZATION, BaiduV1Singer.sign(uri, "POST", new HashMap<>(), hashMap));
// 执行请求并获取HttpResponse对象
HttpResponse httpResponse = httpclient.execute(httpPost);
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
// 打印响应内容
System.out.println("Response content: " + EntityUtils.toString(entity));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
// 关闭HttpClient连接
}
}
AWS版本
核心代码
import org.apache.http.HttpHeaders;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class AwsApacheHttpClientSigner {
!!!替换为百度智能云账户下的ak和sk
private static final String ACCESS_KEY = "your_ak";
private static final String SECRET_KEY = "your_sk";
private static final String CONTENT_TYPE = "application/json";
/**
* 固定值
*/
private static final String REGION = "us-east-1";
/**
* 固定值
*/
private static final String SERVICE = "execute-api";
/**
* 生成带有签名的请求
*
* @param httpPost 需要签名的请求
* @param requestBody 请求体
* @return 带有签名的请求
* @throws Exception 签名过程中可能发生的异常
*/
public static void getSignedRequest(HttpPost httpPost, String requestBody) throws Exception {
String format = getAuthDate();
String authorizationHeader = getAuthorizationHeader(httpPost.getURI().toString(), httpPost.getMethod(), requestBody,
format);
httpPost.addHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE);
httpPost.addHeader(HttpHeaders.AUTHORIZATION, authorizationHeader);
httpPost.addHeader("X-Amz-Content-Sha256", calculateSHA256(requestBody));
httpPost.addHeader("X-Amz-Date", format);
httpPost.setEntity(new StringEntity(requestBody));
}
private static String getAuthDate() {
return LocalDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
}
public static String getAuthorizationHeader(String url, String method, String requestBody, String amzDate) throws Exception {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new Exception("Invalid URL: " + url);
}
String host = uri.getAuthority();
String canonicalUri = uri.getPath();
String canonicalQuerystring = uri.getQuery();
String contentHash = calculateSHA256(requestBody);
String canonicalHeaders = "content-type:" + CONTENT_TYPE + "\n" +
"host:" + host + "\n" +
"x-amz-content-sha256:" + contentHash + "\n" +
"x-amz-date:" + amzDate + "\n";
String signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
String canonicalRequest = method + "\n" + canonicalUri + "\n" + (canonicalQuerystring == null ? "" : canonicalQuerystring) + "\n" +
canonicalHeaders + "\n" + signedHeaders + "\n" + contentHash;
String credentialScope = amzDate.substring(0, 8) + "/" + REGION + "/" + SERVICE + "/aws4_request";
String stringToSign = "AWS4-HMAC-SHA256\n" + amzDate + "\n" + credentialScope + "\n" +
calculateSHA256(canonicalRequest);
byte[] signingKey = getSigningKey(amzDate.substring(0, 8));
String signature = calculateHMAC(stringToSign, signingKey);
return "AWS4-HMAC-SHA256 Credential=" + ACCESS_KEY + "/" + credentialScope + ", " +
"SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
}
private static String calculateSHA256(String text) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
private static byte[] getSigningKey(String dateStamp) throws Exception {
byte[] kSecret = ("AWS4" + SECRET_KEY).getBytes(StandardCharsets.UTF_8);
byte[] kDate = hmacSHA256(dateStamp, kSecret);
byte[] kRegion = hmacSHA256(REGION, kDate);
byte[] kService = hmacSHA256(SERVICE, kRegion);
return hmacSHA256("aws4_request", kService);
}
private static byte[] hmacSHA256(String data, byte[] key) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
mac.init(keySpec);
return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
}
private static String calculateHMAC(String data, byte[] key) throws Exception {
byte[] hmacData = hmacSHA256(data, key);
return bytesToHex(hmacData);
}
}
1. 名称标识:用于区分不同用户,在sdk包中通过该字段获取对应的库文件,可使用字母和数字,不可以包含其他特殊字符,建议增加特定字段避免重复
2. 编译链工具压缩包:用于进行编译sdk包
3. 解压命令:解压编译链压缩包的命令,例如"tar -xvzf"
4. 编译链前缀:编译链所在的路径前缀,例如"bin/arm-linux-gnueabihf-"
5. 编译选项:如果编译链使用时需要增加额外的编译选项(CFLAGS),请提供
测试代码
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
public class ApacheHttpClientSignerTest {
@Test
public void postApiDemo() {
!!! 业务对应的接口地址
String url = "http://smarthome-bdvs.baidubce.com/v1/dynamicDict/list";
!!! todo: 请求体
String requestBodyStr = "{\n" +
" \"fc\": \"device_fc\",\n" +
" \"pk\": \"device_pk\",\n" +
" \"ak\": \"mock_ak01\",\n" +
" \"normValue\": \"A01\",\n" +
" \"synonymValue\": \"xxxx\"\n" +
"}";
// 创建一个HttpClient对象
try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
// 创建一个HttpGet请求
HttpPost httpPost = new HttpPost(url);
System.out.println("Executing request " + httpPost.getRequestLine());
// 进行百度请求签名
AwsApacheHttpClientSigner.getSignedRequest(httpPost, requestBodyStr);
// 执行请求并获取HttpResponse对象
HttpResponse httpResponse = httpclient.execute(httpPost);
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
// 打印响应内容
System.out.println("Response content: " + EntityUtils.toString(entity));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
// 关闭HttpClient连接
}
}
baiduV1版本(推荐)
核心代码
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
public class BaiduV1Singer {
// todo 修改成自己的ak和sk
private static final String ACCESS_KEY = "your_ak";
private static final String SECRET_KEY = "your_sk";
public static final String HOST = "Host";
public static final String AUTHORIZATION = "Authorization";
public static final String CONTENT_LENGTH = "Content-Length";
public static final String CONTENT_MD5 = "Content-MD5";
public static final String CONTENT_TYPE = "Content-Type";
public static final String BCE_PREFIX = "x-bce-";
private static final String BCE_AUTH_VERSION = "bce-auth-v1";
private static final String DEFAULT_ENCODING = "UTF-8";
private static final Charset UTF8 = Charset.forName(DEFAULT_ENCODING);
private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet();
private static final String[] PERCENT_ENCODED_STRINGS = new String[256];
private static final Set<String> defaultHeadersToSign = new HashSet<>();
private static final java.time.format.DateTimeFormatter formatter =
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
defaultHeadersToSign.add(HOST.toLowerCase());
defaultHeadersToSign.add(CONTENT_LENGTH.toLowerCase());
defaultHeadersToSign.add(CONTENT_TYPE.toLowerCase());
defaultHeadersToSign.add(CONTENT_MD5.toLowerCase());
}
static {
for (int i = 'a'; i <= 'z'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
for (int i = 'A'; i <= 'Z'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
for (int i = '0'; i <= '9'; i++) {
URI_UNRESERVED_CHARACTERS.set(i);
}
URI_UNRESERVED_CHARACTERS.set('-');
URI_UNRESERVED_CHARACTERS.set('.');
URI_UNRESERVED_CHARACTERS.set('_');
URI_UNRESERVED_CHARACTERS.set('~');
for (int i = 0; i < PERCENT_ENCODED_STRINGS.length; ++i) {
PERCENT_ENCODED_STRINGS[i] = String.format("%%%02X", i);
}
}
public static String sign(String uri, String method, Map<String, String> parameters, Map<String, String> headers) {
String authString =
BCE_AUTH_VERSION + "/" + ACCESS_KEY + "/"
+ LocalDateTime.now(ZoneId.of("UTC")).format(formatter) + "/" + 1800;
String signingKey = sha256Hex(SECRET_KEY, authString);
String canonicalURI = getCanonicalURIPath(uri);
String canonicalQueryString = getCanonicalQueryString(parameters, true);
SortedMap<String, String> headersToSign = getHeadersToSign(headers, null);
String canonicalHeader = getCanonicalHeaders(headersToSign);
String signedHeaders;
signedHeaders = String.join(";", headersToSign.keySet());
signedHeaders = signedHeaders.trim().toLowerCase();
String canonicalRequest =
method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeader;
System.out.println("authString :" + authString);
System.out.println("signingKey :" + signingKey);
System.out.println("canonicalRequest: " + canonicalRequest);
// Signing the canonical request using key with sha-256 algorithm.
String signature = sha256Hex(signingKey, canonicalRequest);
return authString + "/" + signedHeaders + "/" + signature;
}
private static String sha256Hex(String signingKey, String stringToSign) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(signingKey.getBytes(UTF8), "HmacSHA256"));
return bytesToHex(mac.doFinal(stringToSign.getBytes(UTF8)));
} catch (Exception e) {
throw new RuntimeException("Fail to generate the signature", e);
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
private static String getCanonicalURIPath(String path) {
if (path == null) {
return "/";
} else if (path.startsWith("/")) {
return normalizePath(path);
} else {
return "/" + normalizePath(path);
}
}
private static String normalize(String value) {
try {
StringBuilder builder = new StringBuilder();
for (byte b : value.getBytes(DEFAULT_ENCODING)) {
if (URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) {
builder.append((char) b);
} else {
builder.append(PERCENT_ENCODED_STRINGS[b & 0xFF]);
}
}
return builder.toString();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private static String normalizePath(String path) {
return normalize(path).replace("%2F", "/");
}
private static String getCanonicalQueryString(Map<String, String> parameters, boolean forSignature) {
if (parameters.isEmpty()) {
return "";
}
List<String> parameterStrings = new ArrayList<>();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
if (forSignature && AUTHORIZATION.equalsIgnoreCase(entry.getKey())) {
continue;
}
String key = entry.getKey();
checkNotNull(key, "parameter key should not be null");
String value = entry.getValue();
if (value == null) {
if (forSignature) {
parameterStrings.add(normalize(key) + '=');
} else {
parameterStrings.add(normalize(key));
}
} else {
parameterStrings.add(normalize(key) + '=' + normalize(value));
}
}
Collections.sort(parameterStrings);
return String.join("&", parameterStrings);
}
private static <T> T checkNotNull(T reference, Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
} else {
return reference;
}
}
private static SortedMap<String, String> getHeadersToSign(Map<String, String> headers, Set<String> headersToSign) {
SortedMap<String, String> ret = new TreeMap<>();
if (headersToSign != null) {
Set<String> tempSet = new HashSet<>();
for (String header : headersToSign) {
tempSet.add(header.trim().toLowerCase());
}
headersToSign = tempSet;
}
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
if (entry.getValue() != null && !entry.getValue().isEmpty()) {
if ((headersToSign == null && isDefaultHeaderToSign(key))
|| (headersToSign != null && headersToSign.contains(key.toLowerCase())
&& !AUTHORIZATION.equalsIgnoreCase(key))) {
ret.put(key, entry.getValue());
}
}
}
return ret;
}
private static boolean isDefaultHeaderToSign(String header) {
header = header.trim().toLowerCase();
return header.startsWith(BCE_PREFIX) || defaultHeadersToSign.contains(header);
}
private static String getCanonicalHeaders(SortedMap<String, String> headers) {
if (headers.isEmpty()) {
return "";
}
List<String> headerStrings = new ArrayList<>();
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
if (key == null) {
continue;
}
String value = entry.getValue();
if (value == null) {
value = "";
}
headerStrings.add(normalize(key.trim().toLowerCase()) + ':' + normalize(value.trim()));
}
Collections.sort(headerStrings);
return String.join("\n", headerStrings);
}
}
测试代码
import org.junit.Test;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class BaiduV1SignerTest {
@Test
public void postApiTest() throws Exception {
// todo: host
String host = "smarthome-bdvs.baidubce.com";
// todo: 请求地址
String uri = "/v1/dynamicDict/list";
// todo: 请求体
String requestBodyStr = "{\n" +
" \"fc\": \"device_fc\",\n" +
" \"pk\": \"device_pk\",\n" +
" \"ak\": \"mock_ak01\",\n" +
" \"normValue\": \"A01\",\n" +
" \"synonymValue\": \"xxxx\"\n" +
"}";
String urls = "https://" + host + uri;
// 创建一个URL对象
URL url = new URL(urls);
Map<String, String> hashMap = new HashMap<>();
hashMap.put("Content-Type", "application/json");
hashMap.put("Host", host);
// 使用URL对象创建一个URLConnection对象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", BaiduV1Singer.sign(uri, "POST", new HashMap<>(), hashMap));
// 发送POST请求必须设置如下两行
connection.setDoOutput(true);
connection.setDoInput(true);
// 获取输出流
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes(requestBodyStr);
out.flush();
out.close();
// 从URLConnection对象获取输入流
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
AWS版本
核心代码
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.HttpURLConnection;
import java.net.URI;~~~~
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class BaiduUrlConnectionSigner {
private static final String ACCESS_KEY = "your_ak";
private static final String SECRET_KEY = "your_sk";
private static final String CONTENT_TYPE = "application/json";
/**
* 固定值
*/
private static final String REGION = "us-east-1";
/**
* 固定值
*/
private static final String SERVICE = "execute-api";
/**
* 生成带有签名的请求
*
* @param connection 需要签名的请求
* @param requestBody 请求体
* @return 带有签名的请求
* @throws Exception 签名过程中可能发生的异常
*/
public static void getSignedRequest(HttpURLConnection connection, String requestBody) throws Exception {
String format = getAuthDate();
String authorizationHeader = getAuthorizationHeader(connection.getURL().toString(), connection.getRequestMethod(), requestBody,
format);
connection.setRequestProperty("Content-Type", CONTENT_TYPE);
connection.setRequestProperty("Authorization", authorizationHeader);
connection.setRequestProperty("X-Amz-Content-Sha256", calculateSHA256(requestBody));
connection.setRequestProperty("X-Amz-Date", format);
}
private static String getAuthDate() {
return LocalDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
}
public static String getAuthorizationHeader(String url, String method, String requestBody, String amzDate) throws Exception {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new Exception("Invalid URL: " + url);
}
String host = uri.getAuthority();
String canonicalUri = uri.getPath();
String canonicalQuerystring = uri.getQuery();
String contentHash = calculateSHA256(requestBody);
String canonicalHeaders = "content-type:" + CONTENT_TYPE + "\n" +
"host:" + host + "\n" +
"x-amz-content-sha256:" + contentHash + "\n" +
"x-amz-date:" + amzDate + "\n";
String signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
String canonicalRequest = method + "\n" + canonicalUri + "\n" + (canonicalQuerystring == null ? "" : canonicalQuerystring) + "\n" +
canonicalHeaders + "\n" + signedHeaders + "\n" + contentHash;
String credentialScope = amzDate.substring(0, 8) + "/" + REGION + "/" + SERVICE + "/aws4_request";
String stringToSign = "AWS4-HMAC-SHA256\n" + amzDate + "\n" + credentialScope + "\n" +
calculateSHA256(canonicalRequest);
byte[] signingKey = getSigningKey(amzDate.substring(0, 8));
String signature = calculateHMAC(stringToSign, signingKey);
return "AWS4-HMAC-SHA256 Credential=" + ACCESS_KEY + "/" + credentialScope + ", " +
"SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
}
private static String calculateSHA256(String text) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
private static byte[] getSigningKey(String dateStamp) throws Exception {
byte[] kSecret = ("AWS4" + SECRET_KEY).getBytes(StandardCharsets.UTF_8);
byte[] kDate = hmacSHA256(dateStamp, kSecret);
byte[] kRegion = hmacSHA256(REGION, kDate);
byte[] kService = hmacSHA256(SERVICE, kRegion);
return hmacSHA256("aws4_request", kService);
}
private static byte[] hmacSHA256(String data, byte[] key) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
mac.init(keySpec);
return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
}
private static String calculateHMAC(String data, byte[] key) throws Exception {
byte[] hmacData = hmacSHA256(data, key);
return bytesToHex(hmacData);
}
}
测试代码
import org.junit.Test;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class URLConnectionSignerTest {
@Test
public void postApiTest() throws Exception {
// todo: 请求地址
String urls = "http://smarthome-bdvs.baidubce.com/v1/dynamicDict/list";
// todo: 请求体
String requestBodyStr = "{\n" +
" \"fc\": \"device_fc\",\n" +
" \"pk\": \"device_pk\",\n" +
" \"ak\": \"mock_ak01\",\n" +
" \"normValue\": \"A01\",\n" +
" \"synonymValue\": \"xxxx\"\n" +
"}";
// 创建一个URL对象
URL url = new URL(urls);
// 使用URL对象创建一个URLConnection对象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
// 设置请求签名。
BaiduUrlConnectionSigner.getSignedRequest(connection, requestBodyStr);
// 发送POST请求必须设置如下两行
connection.setDoOutput(true);
connection.setDoInput(true);
// 获取输出流
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes(requestBodyStr);
out.flush();
out.close();
// 从URLConnection对象获取输入流
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}