百度智能云鉴权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依赖
                Java
                
            
            1        <dependency>
2            <groupId>com.squareup.okhttp3</groupId>
3            <artifactId>okhttp</artifactId>
4            <version>4.12.0</version>
5        </dependency>
6        <dependency>
7            <groupId>junit</groupId>
8            <artifactId>junit</artifactId>
9            <version>4.13.2</version>
10        </dependency>baiduV1版本(推荐)
核心代码
                Java
                
            
            1import javax.crypto.Mac;
2import javax.crypto.spec.SecretKeySpec;
3import java.io.UnsupportedEncodingException;
4import java.nio.charset.Charset;
5import java.time.LocalDateTime;
6import java.time.ZoneId;
7import java.util.ArrayList;
8import java.util.BitSet;
9import java.util.Collections;
10import java.util.HashSet;
11import java.util.List;
12import java.util.Map;
13import java.util.Set;
14import java.util.SortedMap;
15import java.util.TreeMap;
16
17
18public class BaiduV1Singer {
19
20    !!! todo 修改成自己的ak和sk
21
22    private static final String ACCESS_KEY = "your_ak";
23    private static final String SECRET_KEY = "your_sk";
24
25
26
27
28    public static final String HOST = "Host";
29    public static final String AUTHORIZATION = "Authorization";
30    public static final String CONTENT_LENGTH = "Content-Length";
31    public static final String CONTENT_MD5 = "Content-MD5";
32    public static final String CONTENT_TYPE = "Content-Type";
33    public static final String BCE_PREFIX = "x-bce-";
34
35    private static final String BCE_AUTH_VERSION = "bce-auth-v1";
36    private static final String DEFAULT_ENCODING = "UTF-8";
37    private static final Charset UTF8 = Charset.forName(DEFAULT_ENCODING);
38    private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet();
39    private static final String[] PERCENT_ENCODED_STRINGS = new String[256];
40    private static final Set<String> defaultHeadersToSign = new HashSet<>();
41    private static final java.time.format.DateTimeFormatter formatter =
42            java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
43
44
45    static {
46        defaultHeadersToSign.add(HOST.toLowerCase());
47        defaultHeadersToSign.add(CONTENT_LENGTH.toLowerCase());
48        defaultHeadersToSign.add(CONTENT_TYPE.toLowerCase());
49        defaultHeadersToSign.add(CONTENT_MD5.toLowerCase());
50    }
51
52    static {
53        for (int i = 'a'; i <= 'z'; i++) {
54            URI_UNRESERVED_CHARACTERS.set(i);
55        }
56        for (int i = 'A'; i <= 'Z'; i++) {
57            URI_UNRESERVED_CHARACTERS.set(i);
58        }
59        for (int i = '0'; i <= '9'; i++) {
60            URI_UNRESERVED_CHARACTERS.set(i);
61        }
62        URI_UNRESERVED_CHARACTERS.set('-');
63        URI_UNRESERVED_CHARACTERS.set('.');
64        URI_UNRESERVED_CHARACTERS.set('_');
65        URI_UNRESERVED_CHARACTERS.set('~');
66
67        for (int i = 0; i < PERCENT_ENCODED_STRINGS.length; ++i) {
68            PERCENT_ENCODED_STRINGS[i] = String.format("%%%02X", i);
69        }
70    }
71
72    public static String sign(String uri, String method, Map<String, String> parameters, Map<String, String> headers) {
73
74        String authString =
75                BCE_AUTH_VERSION + "/" + ACCESS_KEY + "/"
76                        + LocalDateTime.now(ZoneId.of("UTC")).format(formatter) + "/" + 1800;
77        String signingKey = sha256Hex(SECRET_KEY, authString);
78
79        String canonicalURI = getCanonicalURIPath(uri);
80
81        String canonicalQueryString = getCanonicalQueryString(parameters, true);
82
83        SortedMap<String, String> headersToSign = getHeadersToSign(headers, null);
84
85        String canonicalHeader = getCanonicalHeaders(headersToSign);
86
87        String signedHeaders;
88        signedHeaders = String.join(";", headersToSign.keySet());
89        signedHeaders = signedHeaders.trim().toLowerCase();
90
91        String canonicalRequest =
92                method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeader;
93
94        System.out.println("authString :" + authString);
95        System.out.println("signingKey :" + signingKey);
96        System.out.println("canonicalRequest: " + canonicalRequest);
97
98        // Signing the canonical request using key with sha-256 algorithm.
99        String signature = sha256Hex(signingKey, canonicalRequest);
100
101        return authString + "/" + signedHeaders + "/" + signature;
102    }
103
104
105    private static String sha256Hex(String signingKey, String stringToSign) {
106        try {
107            Mac mac = Mac.getInstance("HmacSHA256");
108            mac.init(new SecretKeySpec(signingKey.getBytes(UTF8), "HmacSHA256"));
109            return bytesToHex(mac.doFinal(stringToSign.getBytes(UTF8)));
110        } catch (Exception e) {
111            throw new RuntimeException("Fail to generate the signature", e);
112        }
113    }
114    private static String bytesToHex(byte[] bytes) {
115        StringBuilder result = new StringBuilder();
116        for (byte b : bytes) {
117            result.append(String.format("%02x", b));
118        }
119        return result.toString();
120    }
121    private static String getCanonicalURIPath(String path) {
122        if (path == null) {
123            return "/";
124        } else if (path.startsWith("/")) {
125            return normalizePath(path);
126        } else {
127            return "/" + normalizePath(path);
128        }
129    }
130
131    private static String normalize(String value) {
132        try {
133            StringBuilder builder = new StringBuilder();
134            for (byte b : value.getBytes(DEFAULT_ENCODING)) {
135                if (URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) {
136                    builder.append((char) b);
137                } else {
138                    builder.append(PERCENT_ENCODED_STRINGS[b & 0xFF]);
139                }
140            }
141            return builder.toString();
142        } catch (UnsupportedEncodingException e) {
143            throw new RuntimeException(e);
144        }
145    }
146
147    private static String normalizePath(String path) {
148        return normalize(path).replace("%2F", "/");
149    }
150
151
152    private static String getCanonicalQueryString(Map<String, String> parameters, boolean forSignature) {
153        if (parameters.isEmpty()) {
154            return "";
155        }
156
157        List<String> parameterStrings = new ArrayList<>();
158        for (Map.Entry<String, String> entry : parameters.entrySet()) {
159            if (forSignature && AUTHORIZATION.equalsIgnoreCase(entry.getKey())) {
160                continue;
161            }
162            String key = entry.getKey();
163            checkNotNull(key, "parameter key should not be null");
164            String value = entry.getValue();
165            if (value == null) {
166                if (forSignature) {
167                    parameterStrings.add(normalize(key) + '=');
168                } else {
169                    parameterStrings.add(normalize(key));
170                }
171            } else {
172                parameterStrings.add(normalize(key) + '=' + normalize(value));
173            }
174        }
175        Collections.sort(parameterStrings);
176
177        return String.join("&",parameterStrings);
178    }
179
180    private static <T> T checkNotNull(T reference, Object errorMessage) {
181        if (reference == null) {
182            throw new NullPointerException(String.valueOf(errorMessage));
183        } else {
184            return reference;
185        }
186    }
187
188    private static SortedMap<String, String> getHeadersToSign(Map<String, String> headers, Set<String> headersToSign) {
189        SortedMap<String, String> ret = new TreeMap<>();
190        if (headersToSign != null) {
191            Set<String> tempSet = new HashSet<>();
192            for (String header : headersToSign) {
193                tempSet.add(header.trim().toLowerCase());
194            }
195            headersToSign = tempSet;
196        }
197        for (Map.Entry<String, String> entry : headers.entrySet()) {
198            String key = entry.getKey();
199            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
200                if ((headersToSign == null && isDefaultHeaderToSign(key))
201                        || (headersToSign != null && headersToSign.contains(key.toLowerCase())
202                        && !AUTHORIZATION.equalsIgnoreCase(key))) {
203                    ret.put(key, entry.getValue());
204                }
205            }
206        }
207        return ret;
208    }
209
210    private static boolean isDefaultHeaderToSign(String header) {
211        header = header.trim().toLowerCase();
212        return header.startsWith(BCE_PREFIX) || defaultHeadersToSign.contains(header);
213    }
214
215    private static String getCanonicalHeaders(SortedMap<String, String> headers) {
216        if (headers.isEmpty()) {
217            return "";
218        }
219
220        List<String> headerStrings = new ArrayList<>();
221        for (Map.Entry<String, String> entry : headers.entrySet()) {
222            String key = entry.getKey();
223            if (key == null) {
224                continue;
225            }
226            String value = entry.getValue();
227            if (value == null) {
228                value = "";
229            }
230            headerStrings.add(normalize(key.trim().toLowerCase()) + ':' + normalize(value.trim()));
231        }
232        Collections.sort(headerStrings);
233
234        return String.join("\n", headerStrings);
235    }
236
237}测试代码
                Java
                
            
            1import okhttp3.MediaType;
2import okhttp3.OkHttpClient;
3import okhttp3.Request;
4import okhttp3.RequestBody;
5import okhttp3.Response;
6import org.intellij.lang.annotations.Language;
7import org.junit.Test;
8
9import java.nio.charset.StandardCharsets;
10import java.util.HashMap;
11import java.util.Map;
12
13import static com.baidu.duhome.BaiduV1Singer.sign;
14import static com.sun.deploy.net.HttpRequest.CONTENT_TYPE;
15
16public class BaiduV1SingerTest {
17
18
19    @Test
20    public void okhttpPostTest() throws Exception {
21        
22        String host = "smarthome-bdvs.baidubce.com";
23        
24        !!! 具体的业务接口
25        String uri = "/v1/dynamicDict/list";
26
27        String url = "https://" + host + uri;
28
29        !!! todo: 请求体
30        @Language("JSON") String requestBody = "{\n" +
31                "  \"fc\": \"device_fc\",\n" +
32                "  \"pk\": \"device_pk\",\n" +
33                "  \"ak\": \"mock_ak02\",\n" +
34                "  \"normValue\": \"A01\",\n" +
35                "  \"synonymValue\": \"xxxx" +
36                "\"\n" +
37                "}";
38
39        Map<String, String> hashMap = new HashMap<>();
40        hashMap.put("Content-Type", "application/json");
41        hashMap.put("HOST", host);
42
43        OkHttpClient client = new OkHttpClient();
44        MediaType mediaType = MediaType.parse(CONTENT_TYPE);
45        Request request = new Request.Builder()
46                .header("Content-Type", "application/json")
47                .header("Host", host)
48                .header("Authorization", sign(uri, "POST", new HashMap<>(), hashMap))
49                //     构建requestBody 不能使用字符的方法,可以使用字节数组或者流的方式,字符串的方法中会强制在请求头中增加 charaset=urf8; 导致鉴权失败
50                .post(RequestBody.create(requestBody.getBytes(StandardCharsets.UTF_8), mediaType))
51                .url(url)
52                .build();
53
54
55        try (Response execute = client.newCall(request).execute()) {
56            String string = null;
57            if (execute.body() != null) {
58                string = execute.body().string();
59            }
60            System.out.println(string);
61        }
62
63    }
64
65    @Test
66    public void okhttpGetTest() throws Exception {
67        String host = "smarthome-bdvs.baidubce.com";
68        String uri = "/v1/foo";
69        String url = "http://" + host + uri;
70
71        Map<String, String> hashMap = new HashMap<>();
72        hashMap.put("HOST", host);
73
74        OkHttpClient client = new OkHttpClient();
75        Request request = new Request.Builder()
76                .header("Host", host)
77                .header("Authorization", sign(uri, "GET", new HashMap<>(), hashMap))
78                .get()
79                .url(url)
80                .build();
81
82        try (Response execute = client.newCall(request).execute()) {
83            String string = null;
84            if (execute.body() != null) {
85                string = execute.body().string();
86            }
87            System.out.println(string);
88        }
89    }
90
91}AWS版本
核心代码
                Java
                
            
            1import okhttp3.Request;
2
3import javax.crypto.Mac;
4import javax.crypto.spec.SecretKeySpec;
5import java.net.URI;
6import java.net.URISyntaxException;
7import java.nio.charset.StandardCharsets;
8import java.security.MessageDigest;
9import java.security.NoSuchAlgorithmException;
10import java.time.LocalDateTime;
11import java.time.ZoneId;
12import java.time.format.DateTimeFormatter;
13
14public class AwsOkhttp3Signer {
15
16    private static final String ACCESS_KEY = "your_ak";
17    private static final String SECRET_KEY = "your_sk";
18
19
20    private static final String CONTENT_TYPE = "application/json";
21
22    /**
23     * 固定值
24     */
25    private static final String REGION = "us-east-1";
26
27    /**
28     * 固定值
29     */
30    private static final String SERVICE = "execute-api";
31
32
33    /**
34     * 生成带有签名的请求
35     *
36     * @param request     需要签名的请求
37     * @param requestBody 请求体
38     * @return 带有签名的请求
39     * @throws Exception 签名过程中可能发生的异常
40     */
41    public static Request getSignedRequest(Request request, String requestBody) throws Exception {
42        String format = getAuthDate();
43        String authorizationHeader = getAuthorizationHeader(request.url().toString(), request.method(), requestBody, format);
44        return request.newBuilder()
45                .addHeader("Content-Type", CONTENT_TYPE)
46                .addHeader("Authorization", authorizationHeader)
47                .addHeader("X-Amz-Content-Sha256", calculateSHA256(requestBody))
48                .addHeader("X-Amz-Date", format)
49                .build();
50    }
51
52
53    private static String getAuthDate() {
54        return LocalDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
55    }
56
57    public static String getAuthorizationHeader(String url, String method, String requestBody, String amzDate) throws Exception {
58
59        URI uri;
60        try {
61            uri = new URI(url);
62        } catch (URISyntaxException e) {
63            throw new Exception("Invalid URL: " + url);
64        }
65        String host = uri.getAuthority();
66        String canonicalUri = uri.getPath();
67        String canonicalQuerystring = uri.getQuery();
68        String contentHash = calculateSHA256(requestBody);
69
70        String canonicalHeaders = "content-type:" + CONTENT_TYPE + "\n" +
71                "host:" + host + "\n" +
72                "x-amz-content-sha256:" + contentHash + "\n" +
73                "x-amz-date:" + amzDate + "\n";
74
75        String signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
76        String canonicalRequest = method + "\n" + canonicalUri + "\n" + (canonicalQuerystring == null ? "" : canonicalQuerystring) + "\n" +
77                canonicalHeaders + "\n" + signedHeaders + "\n" + contentHash;
78        String credentialScope = amzDate.substring(0, 8) + "/" + REGION + "/" + SERVICE + "/aws4_request";
79        String stringToSign = "AWS4-HMAC-SHA256\n" + amzDate + "\n" + credentialScope + "\n" +
80                calculateSHA256(canonicalRequest);
81
82        byte[] signingKey = getSigningKey(amzDate.substring(0, 8));
83        String signature = calculateHMAC(stringToSign, signingKey);
84
85        return "AWS4-HMAC-SHA256 Credential=" + ACCESS_KEY + "/" + credentialScope + ", " +
86                "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
87    }
88
89    private static String calculateSHA256(String text) throws NoSuchAlgorithmException {
90        MessageDigest digest = MessageDigest.getInstance("SHA-256");
91        byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
92        return bytesToHex(hash);
93    }
94
95    private static String bytesToHex(byte[] bytes) {
96        StringBuilder result = new StringBuilder();
97        for (byte b : bytes) {
98            result.append(String.format("%02x", b));
99        }
100        return result.toString();
101    }
102
103    private static byte[] getSigningKey(String dateStamp) throws Exception {
104        byte[] kSecret = ("AWS4" + SECRET_KEY).getBytes(StandardCharsets.UTF_8);
105        byte[] kDate = hmacSHA256(dateStamp, kSecret);
106        byte[] kRegion = hmacSHA256(REGION, kDate);
107        byte[] kService = hmacSHA256(SERVICE, kRegion);
108        return hmacSHA256("aws4_request", kService);
109    }
110
111    private static byte[] hmacSHA256(String data, byte[] key) throws Exception {
112        Mac mac = Mac.getInstance("HmacSHA256");
113        SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
114        mac.init(keySpec);
115        return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
116    }
117
118    private static String calculateHMAC(String data, byte[] key) throws Exception {
119        byte[] hmacData = hmacSHA256(data, key);
120        return bytesToHex(hmacData);
121    }
122
123
124}测试代码
                Java
                
            
            1import okhttp3.MediaType;
2import okhttp3.OkHttpClient;
3import okhttp3.Request;
4import okhttp3.RequestBody;
5import okhttp3.Response;
6
7import java.nio.charset.StandardCharsets;
8
9import static com.baidu.duhome.AwsOkhttp3Signer.getSignedRequest;
10import static com.sun.deploy.net.HttpRequest.CONTENT_TYPE;
11
12public class Okhhtp3SignerTest {
13
14    @org.junit.Test
15    public void postApiTest() throws Exception {
16        !!! 具体业务地址
17        String url = "http://smarthome-bdvs.baidubce.com/v1/dynamicDict/list";
18
19        !!! todo: 请求体
20        String requestBody = "{\n" +
21                "  \"fc\": \"device_fc\",\n" +
22                "  \"pk\": \"device_pk\",\n" +
23                "  \"ak\": \"mock_ak01\",\n" +
24                "  \"normValue\": \"A01\",\n" +
25                "  \"synonymValue\": \"xxxx\"\n" +
26                "}";
27
28        OkHttpClient client = new OkHttpClient();
29        MediaType mediaType = MediaType.parse(CONTENT_TYPE);
30        Request request = new Request.Builder()
31                //     构建requestBody 不能使用字符的方法,可以使用字节数组或者流的方式,字符串的方法中会强制在请求头中增加 charaset=urf8; 导致鉴权失败
32                .post(RequestBody.create(requestBody.getBytes(StandardCharsets.UTF_8), mediaType))
33                .url(url)
34                .build();
35
36        // (进行签名) 注意会生成一个新的Request对象。
37        request = getSignedRequest(request, requestBody);
38
39        try (Response execute = client.newCall(request).execute()) {
40            String string = null;
41            if (execute.body() != null) {
42                string = execute.body().string();
43            }
44            System.out.println(string);
45        }
46
47    }
48}ApacheHttpClient示例
Maven依赖
                Java
                
            
            1        <dependency>
2            <groupId>org.apache.httpcomponents</groupId>
3            <artifactId>httpclient</artifactId>
4            <version>4.5.13</version>
5        </dependency>
6        <dependency>
7            <groupId>junit</groupId>
8            <artifactId>junit</artifactId>
9            <version>4.13.2</version>
10        </dependency>baiduV1版本(推荐)
核心代码
                Java
                
            
            1import javax.crypto.Mac;
2import javax.crypto.spec.SecretKeySpec;
3import java.io.UnsupportedEncodingException;
4import java.nio.charset.Charset;
5import java.time.LocalDateTime;
6import java.time.ZoneId;
7import java.util.ArrayList;
8import java.util.BitSet;
9import java.util.Collections;
10import java.util.HashSet;
11import java.util.List;
12import java.util.Map;
13import java.util.Set;
14import java.util.SortedMap;
15import java.util.TreeMap;
16
17
18public class BaiduV1Singer {
19
20    !!! todo 修改成自己的ak和sk
21    private static final String ACCESS_KEY = "your_ak";
22    private static final String SECRET_KEY = "your_sk";
23
24
25    public static final String HOST = "Host";
26    public static final String AUTHORIZATION = "Authorization";
27    public static final String CONTENT_LENGTH = "Content-Length";
28    public static final String CONTENT_MD5 = "Content-MD5";
29    public static final String CONTENT_TYPE = "Content-Type";
30    public static final String BCE_PREFIX = "x-bce-";
31
32    private static final String BCE_AUTH_VERSION = "bce-auth-v1";
33    private static final String DEFAULT_ENCODING = "UTF-8";
34    private static final Charset UTF8 = Charset.forName(DEFAULT_ENCODING);
35    private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet();
36    private static final String[] PERCENT_ENCODED_STRINGS = new String[256];
37    private static final Set<String> defaultHeadersToSign = new HashSet<>();
38    private static final java.time.format.DateTimeFormatter formatter =
39            java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
40
41
42    static {
43        defaultHeadersToSign.add(HOST.toLowerCase());
44        defaultHeadersToSign.add(CONTENT_LENGTH.toLowerCase());
45        defaultHeadersToSign.add(CONTENT_TYPE.toLowerCase());
46        defaultHeadersToSign.add(CONTENT_MD5.toLowerCase());
47    }
48
49    static {
50        for (int i = 'a'; i <= 'z'; i++) {
51            URI_UNRESERVED_CHARACTERS.set(i);
52        }
53        for (int i = 'A'; i <= 'Z'; i++) {
54            URI_UNRESERVED_CHARACTERS.set(i);
55        }
56        for (int i = '0'; i <= '9'; i++) {
57            URI_UNRESERVED_CHARACTERS.set(i);
58        }
59        URI_UNRESERVED_CHARACTERS.set('-');
60        URI_UNRESERVED_CHARACTERS.set('.');
61        URI_UNRESERVED_CHARACTERS.set('_');
62        URI_UNRESERVED_CHARACTERS.set('~');
63
64        for (int i = 0; i < PERCENT_ENCODED_STRINGS.length; ++i) {
65            PERCENT_ENCODED_STRINGS[i] = String.format("%%%02X", i);
66        }
67    }
68
69    public static String sign(String uri, String method, Map<String, String> parameters, Map<String, String> headers) {
70
71        String authString =
72                BCE_AUTH_VERSION + "/" + ACCESS_KEY + "/"
73                        + LocalDateTime.now(ZoneId.of("UTC")).format(formatter) + "/" + 1800;
74        String signingKey = sha256Hex(SECRET_KEY, authString);
75
76        String canonicalURI = getCanonicalURIPath(uri);
77
78        String canonicalQueryString = getCanonicalQueryString(parameters, true);
79
80        SortedMap<String, String> headersToSign = getHeadersToSign(headers, null);
81
82        String canonicalHeader = getCanonicalHeaders(headersToSign);
83
84        String signedHeaders;
85        signedHeaders = String.join(";", headersToSign.keySet());
86        signedHeaders = signedHeaders.trim().toLowerCase();
87
88        String canonicalRequest =
89                method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeader;
90
91        System.out.println("authString :" + authString);
92        System.out.println("signingKey :" + signingKey);
93        System.out.println("canonicalRequest: " + canonicalRequest);
94
95        // Signing the canonical request using key with sha-256 algorithm.
96        String signature = sha256Hex(signingKey, canonicalRequest);
97
98        return authString + "/" + signedHeaders + "/" + signature;
99    }
100
101
102    private static String sha256Hex(String signingKey, String stringToSign) {
103        try {
104            Mac mac = Mac.getInstance("HmacSHA256");
105            mac.init(new SecretKeySpec(signingKey.getBytes(UTF8), "HmacSHA256"));
106            return bytesToHex(mac.doFinal(stringToSign.getBytes(UTF8)));
107        } catch (Exception e) {
108            throw new RuntimeException("Fail to generate the signature", e);
109        }
110    }
111
112    private static String bytesToHex(byte[] bytes) {
113        StringBuilder result = new StringBuilder();
114        for (byte b : bytes) {
115            result.append(String.format("%02x", b));
116        }
117        return result.toString();
118    }
119
120    private static String getCanonicalURIPath(String path) {
121        if (path == null) {
122            return "/";
123        } else if (path.startsWith("/")) {
124            return normalizePath(path);
125        } else {
126            return "/" + normalizePath(path);
127        }
128    }
129
130    private static String normalize(String value) {
131        try {
132            StringBuilder builder = new StringBuilder();
133            for (byte b : value.getBytes(DEFAULT_ENCODING)) {
134                if (URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) {
135                    builder.append((char) b);
136                } else {
137                    builder.append(PERCENT_ENCODED_STRINGS[b & 0xFF]);
138                }
139            }
140            return builder.toString();
141        } catch (UnsupportedEncodingException e) {
142            throw new RuntimeException(e);
143        }
144    }
145
146    private static String normalizePath(String path) {
147        return normalize(path).replace("%2F", "/");
148    }
149
150
151    private static String getCanonicalQueryString(Map<String, String> parameters, boolean forSignature) {
152        if (parameters.isEmpty()) {
153            return "";
154        }
155
156        List<String> parameterStrings = new ArrayList<>();
157        for (Map.Entry<String, String> entry : parameters.entrySet()) {
158            if (forSignature && AUTHORIZATION.equalsIgnoreCase(entry.getKey())) {
159                continue;
160            }
161            String key = entry.getKey();
162            checkNotNull(key, "parameter key should not be null");
163            String value = entry.getValue();
164            if (value == null) {
165                if (forSignature) {
166                    parameterStrings.add(normalize(key) + '=');
167                } else {
168                    parameterStrings.add(normalize(key));
169                }
170            } else {
171                parameterStrings.add(normalize(key) + '=' + normalize(value));
172            }
173        }
174        Collections.sort(parameterStrings);
175
176        return String.join("&", parameterStrings);
177    }
178
179    private static <T> T checkNotNull(T reference, Object errorMessage) {
180        if (reference == null) {
181            throw new NullPointerException(String.valueOf(errorMessage));
182        } else {
183            return reference;
184        }
185    }
186
187    private static SortedMap<String, String> getHeadersToSign(Map<String, String> headers, Set<String> headersToSign) {
188        SortedMap<String, String> ret = new TreeMap<>();
189        if (headersToSign != null) {
190            Set<String> tempSet = new HashSet<>();
191            for (String header : headersToSign) {
192                tempSet.add(header.trim().toLowerCase());
193            }
194            headersToSign = tempSet;
195        }
196        for (Map.Entry<String, String> entry : headers.entrySet()) {
197            String key = entry.getKey();
198            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
199                if ((headersToSign == null && isDefaultHeaderToSign(key))
200                        || (headersToSign != null && headersToSign.contains(key.toLowerCase())
201                        && !AUTHORIZATION.equalsIgnoreCase(key))) {
202                    ret.put(key, entry.getValue());
203                }
204            }
205        }
206        return ret;
207    }
208
209    private static boolean isDefaultHeaderToSign(String header) {
210        header = header.trim().toLowerCase();
211        return header.startsWith(BCE_PREFIX) || defaultHeadersToSign.contains(header);
212    }
213
214    private static String getCanonicalHeaders(SortedMap<String, String> headers) {
215        if (headers.isEmpty()) {
216            return "";
217        }
218
219        List<String> headerStrings = new ArrayList<>();
220        for (Map.Entry<String, String> entry : headers.entrySet()) {
221            String key = entry.getKey();
222            if (key == null) {
223                continue;
224            }
225            String value = entry.getValue();
226            if (value == null) {
227                value = "";
228            }
229            headerStrings.add(normalize(key.trim().toLowerCase()) + ':' + normalize(value.trim()));
230        }
231        Collections.sort(headerStrings);
232
233        return String.join("\n", headerStrings);
234    }
235
236}测试代码
                Java
                
            
            1import org.apache.http.HttpEntity;
2import org.apache.http.HttpHeaders;
3import org.apache.http.HttpResponse;
4import org.apache.http.client.methods.HttpPost;
5import org.apache.http.entity.StringEntity;
6import org.apache.http.impl.client.CloseableHttpClient;
7import org.apache.http.impl.client.HttpClients;
8import org.apache.http.util.EntityUtils;
9import org.junit.Test;
10
11import java.util.HashMap;
12import java.util.Map;
13
14
15public class BaiduV1SingerTest {
16    private static final String CONTENT_TYPE = "application/json";
17
18
19    @Test
20    public void postApiDemo() {
21
22
23        String host = "smarthome-bdvs.baidubce.com";
24        String uri = "/v1/dynamicDict/list";
25
26        String url = "https://" + host + uri;
27
28
29        // todo: 请求体
30        String requestBodyStr = "{\n" +
31                "  \"fc\": \"device_fc\",\n" +
32                "  \"pk\": \"device_pk\",\n" +
33                "  \"ak\": \"mock_ak02\",\n" +
34                "  \"normValue\": \"A01\",\n" +
35                "  \"synonymValue\": \"xxxx" +
36                "\"\n" +
37                "}";
38
39        Map<String, String> hashMap = new HashMap<>();
40        hashMap.put(HttpHeaders.CONTENT_TYPE, "application/json");
41        hashMap.put(HttpHeaders.HOST, host);
42
43        // 创建一个HttpClient对象
44        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
45            // 创建一个HttpGet请求
46            HttpPost httpPost = new HttpPost(url);
47            System.out.println("Executing request " + httpPost.getRequestLine());
48
49            // 进行百度请求签名
50//            AwsApacheHttpClientSigner.getSignedRequest(httpPost, requestBodyStr);
51            httpPost.setEntity(new StringEntity(requestBodyStr));
52            httpPost.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
53            httpPost.addHeader(HttpHeaders.HOST, host);
54            httpPost.addHeader(HttpHeaders.AUTHORIZATION, BaiduV1Singer.sign(uri, "POST", new HashMap<>(), hashMap));
55
56            // 执行请求并获取HttpResponse对象
57            HttpResponse httpResponse = httpclient.execute(httpPost);
58            HttpEntity entity = httpResponse.getEntity();
59
60            if (entity != null) {
61                // 打印响应内容
62                System.out.println("Response content: " + EntityUtils.toString(entity));
63            }
64        } catch (Exception e) {
65            throw new RuntimeException(e);
66        }
67        // 关闭HttpClient连接
68    }
69
70
71}AWS版本
核心代码
                Java
                
            
            1import org.apache.http.HttpHeaders;
2import org.apache.http.client.methods.HttpPost;
3import org.apache.http.entity.StringEntity;
4
5import javax.crypto.Mac;
6import javax.crypto.spec.SecretKeySpec;
7import java.net.URI;
8import java.net.URISyntaxException;
9import java.nio.charset.StandardCharsets;
10import java.security.MessageDigest;
11import java.security.NoSuchAlgorithmException;
12import java.time.LocalDateTime;
13import java.time.ZoneId;
14import java.time.format.DateTimeFormatter;
15
16public class AwsApacheHttpClientSigner {
17    !!!替换为百度智能云账户下的ak和sk
18    private static final String ACCESS_KEY = "your_ak";
19    private static final String SECRET_KEY = "your_sk";
20
21    private static final String CONTENT_TYPE = "application/json";
22
23    /**
24     * 固定值
25     */
26    private static final String REGION = "us-east-1";
27
28    /**
29     * 固定值
30     */
31    private static final String SERVICE = "execute-api";
32
33
34    /**
35     * 生成带有签名的请求
36     *
37     * @param httpPost    需要签名的请求
38     * @param requestBody 请求体
39     * @return 带有签名的请求
40     * @throws Exception 签名过程中可能发生的异常
41     */
42    public static void getSignedRequest(HttpPost httpPost, String requestBody) throws Exception {
43        String format = getAuthDate();
44        String authorizationHeader = getAuthorizationHeader(httpPost.getURI().toString(), httpPost.getMethod(), requestBody,
45                format);
46        httpPost.addHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE);
47        httpPost.addHeader(HttpHeaders.AUTHORIZATION, authorizationHeader);
48        httpPost.addHeader("X-Amz-Content-Sha256", calculateSHA256(requestBody));
49        httpPost.addHeader("X-Amz-Date", format);
50        httpPost.setEntity(new StringEntity(requestBody));
51    }
52
53
54    private static String getAuthDate() {
55        return LocalDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
56    }
57
58    public static String getAuthorizationHeader(String url, String method, String requestBody, String amzDate) throws Exception {
59
60        URI uri;
61        try {
62            uri = new URI(url);
63        } catch (URISyntaxException e) {
64            throw new Exception("Invalid URL: " + url);
65        }
66        String host = uri.getAuthority();
67        String canonicalUri = uri.getPath();
68        String canonicalQuerystring = uri.getQuery();
69        String contentHash = calculateSHA256(requestBody);
70
71        String canonicalHeaders = "content-type:" + CONTENT_TYPE + "\n" +
72                "host:" + host + "\n" +
73                "x-amz-content-sha256:" + contentHash + "\n" +
74                "x-amz-date:" + amzDate + "\n";
75
76        String signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
77        String canonicalRequest = method + "\n" + canonicalUri + "\n" + (canonicalQuerystring == null ? "" : canonicalQuerystring) + "\n" +
78                canonicalHeaders + "\n" + signedHeaders + "\n" + contentHash;
79        String credentialScope = amzDate.substring(0, 8) + "/" + REGION + "/" + SERVICE + "/aws4_request";
80        String stringToSign = "AWS4-HMAC-SHA256\n" + amzDate + "\n" + credentialScope + "\n" +
81                calculateSHA256(canonicalRequest);
82
83        byte[] signingKey = getSigningKey(amzDate.substring(0, 8));
84        String signature = calculateHMAC(stringToSign, signingKey);
85
86        return "AWS4-HMAC-SHA256 Credential=" + ACCESS_KEY + "/" + credentialScope + ", " +
87                "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
88    }
89
90    private static String calculateSHA256(String text) throws NoSuchAlgorithmException {
91        MessageDigest digest = MessageDigest.getInstance("SHA-256");
92        byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
93        return bytesToHex(hash);
94    }
95
96    private static String bytesToHex(byte[] bytes) {
97        StringBuilder result = new StringBuilder();
98        for (byte b : bytes) {
99            result.append(String.format("%02x", b));
100        }
101        return result.toString();
102    }
103
104    private static byte[] getSigningKey(String dateStamp) throws Exception {
105        byte[] kSecret = ("AWS4" + SECRET_KEY).getBytes(StandardCharsets.UTF_8);
106        byte[] kDate = hmacSHA256(dateStamp, kSecret);
107        byte[] kRegion = hmacSHA256(REGION, kDate);
108        byte[] kService = hmacSHA256(SERVICE, kRegion);
109        return hmacSHA256("aws4_request", kService);
110    }
111
112    private static byte[] hmacSHA256(String data, byte[] key) throws Exception {
113        Mac mac = Mac.getInstance("HmacSHA256");
114        SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
115        mac.init(keySpec);
116        return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
117    }
118
119    private static String calculateHMAC(String data, byte[] key) throws Exception {
120        byte[] hmacData = hmacSHA256(data, key);
121        return bytesToHex(hmacData);
122    }
123
124
125}
                Java
                
            
            11. 名称标识:用于区分不同用户,在sdk包中通过该字段获取对应的库文件,可使用字母和数字,不可以包含其他特殊字符,建议增加特定字段避免重复
22. 编译链工具压缩包:用于进行编译sdk包
33. 解压命令:解压编译链压缩包的命令,例如"tar -xvzf"
44. 编译链前缀:编译链所在的路径前缀,例如"bin/arm-linux-gnueabihf-"
55. 编译选项:如果编译链使用时需要增加额外的编译选项(CFLAGS),请提供测试代码
                Java
                
            
            1import org.apache.http.HttpEntity;
2import org.apache.http.HttpResponse;
3import org.apache.http.client.methods.HttpPost;
4import org.apache.http.impl.client.CloseableHttpClient;
5import org.apache.http.impl.client.HttpClients;
6import org.apache.http.util.EntityUtils;
7import org.junit.Test;
8
9
10public class ApacheHttpClientSignerTest {
11
12
13    @Test
14    public void postApiDemo() {
15        
16        !!! 业务对应的接口地址
17        String url = "http://smarthome-bdvs.baidubce.com/v1/dynamicDict/list";
18
19        !!! todo: 请求体
20        String requestBodyStr = "{\n" +
21                "  \"fc\": \"device_fc\",\n" +
22                "  \"pk\": \"device_pk\",\n" +
23                "  \"ak\": \"mock_ak01\",\n" +
24                "  \"normValue\": \"A01\",\n" +
25                "  \"synonymValue\": \"xxxx\"\n" +
26                "}";
27
28
29        // 创建一个HttpClient对象
30        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
31            // 创建一个HttpGet请求
32            HttpPost httpPost = new HttpPost(url);
33            System.out.println("Executing request " + httpPost.getRequestLine());
34
35            // 进行百度请求签名
36            AwsApacheHttpClientSigner.getSignedRequest(httpPost, requestBodyStr);
37
38            // 执行请求并获取HttpResponse对象
39            HttpResponse httpResponse = httpclient.execute(httpPost);
40            HttpEntity entity = httpResponse.getEntity();
41
42            if (entity != null) {
43                // 打印响应内容
44                System.out.println("Response content: " + EntityUtils.toString(entity));
45            }
46        } catch (Exception e) {
47            throw new RuntimeException(e);
48        }
49        // 关闭HttpClient连接
50    }
51
52}baiduV1版本(推荐)
核心代码
                Java
                
            
            1import javax.crypto.Mac;
2import javax.crypto.spec.SecretKeySpec;
3import java.io.UnsupportedEncodingException;
4import java.nio.charset.Charset;
5import java.time.LocalDateTime;
6import java.time.ZoneId;
7import java.util.ArrayList;
8import java.util.BitSet;
9import java.util.Collections;
10import java.util.HashSet;
11import java.util.List;
12import java.util.Map;
13import java.util.Set;
14import java.util.SortedMap;
15import java.util.TreeMap;
16
17
18public class BaiduV1Singer {
19
20    // todo 修改成自己的ak和sk
21    private static final String ACCESS_KEY = "your_ak";
22    private static final String SECRET_KEY = "your_sk";
23
24
25    public static final String HOST = "Host";
26    public static final String AUTHORIZATION = "Authorization";
27    public static final String CONTENT_LENGTH = "Content-Length";
28    public static final String CONTENT_MD5 = "Content-MD5";
29    public static final String CONTENT_TYPE = "Content-Type";
30    public static final String BCE_PREFIX = "x-bce-";
31
32    private static final String BCE_AUTH_VERSION = "bce-auth-v1";
33    private static final String DEFAULT_ENCODING = "UTF-8";
34    private static final Charset UTF8 = Charset.forName(DEFAULT_ENCODING);
35    private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet();
36    private static final String[] PERCENT_ENCODED_STRINGS = new String[256];
37    private static final Set<String> defaultHeadersToSign = new HashSet<>();
38    private static final java.time.format.DateTimeFormatter formatter =
39            java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
40
41
42    static {
43        defaultHeadersToSign.add(HOST.toLowerCase());
44        defaultHeadersToSign.add(CONTENT_LENGTH.toLowerCase());
45        defaultHeadersToSign.add(CONTENT_TYPE.toLowerCase());
46        defaultHeadersToSign.add(CONTENT_MD5.toLowerCase());
47    }
48
49    static {
50        for (int i = 'a'; i <= 'z'; i++) {
51            URI_UNRESERVED_CHARACTERS.set(i);
52        }
53        for (int i = 'A'; i <= 'Z'; i++) {
54            URI_UNRESERVED_CHARACTERS.set(i);
55        }
56        for (int i = '0'; i <= '9'; i++) {
57            URI_UNRESERVED_CHARACTERS.set(i);
58        }
59        URI_UNRESERVED_CHARACTERS.set('-');
60        URI_UNRESERVED_CHARACTERS.set('.');
61        URI_UNRESERVED_CHARACTERS.set('_');
62        URI_UNRESERVED_CHARACTERS.set('~');
63
64        for (int i = 0; i < PERCENT_ENCODED_STRINGS.length; ++i) {
65            PERCENT_ENCODED_STRINGS[i] = String.format("%%%02X", i);
66        }
67    }
68
69    public static String sign(String uri, String method, Map<String, String> parameters, Map<String, String> headers) {
70
71        String authString =
72                BCE_AUTH_VERSION + "/" + ACCESS_KEY + "/"
73                        + LocalDateTime.now(ZoneId.of("UTC")).format(formatter) + "/" + 1800;
74        String signingKey = sha256Hex(SECRET_KEY, authString);
75
76        String canonicalURI = getCanonicalURIPath(uri);
77
78        String canonicalQueryString = getCanonicalQueryString(parameters, true);
79
80        SortedMap<String, String> headersToSign = getHeadersToSign(headers, null);
81
82        String canonicalHeader = getCanonicalHeaders(headersToSign);
83
84        String signedHeaders;
85        signedHeaders = String.join(";", headersToSign.keySet());
86        signedHeaders = signedHeaders.trim().toLowerCase();
87
88        String canonicalRequest =
89                method + "\n" + canonicalURI + "\n" + canonicalQueryString + "\n" + canonicalHeader;
90
91        System.out.println("authString :" + authString);
92        System.out.println("signingKey :" + signingKey);
93        System.out.println("canonicalRequest: " + canonicalRequest);
94
95        // Signing the canonical request using key with sha-256 algorithm.
96        String signature = sha256Hex(signingKey, canonicalRequest);
97
98        return authString + "/" + signedHeaders + "/" + signature;
99    }
100
101
102    private static String sha256Hex(String signingKey, String stringToSign) {
103        try {
104            Mac mac = Mac.getInstance("HmacSHA256");
105            mac.init(new SecretKeySpec(signingKey.getBytes(UTF8), "HmacSHA256"));
106            return bytesToHex(mac.doFinal(stringToSign.getBytes(UTF8)));
107        } catch (Exception e) {
108            throw new RuntimeException("Fail to generate the signature", e);
109        }
110    }
111
112    private static String bytesToHex(byte[] bytes) {
113        StringBuilder result = new StringBuilder();
114        for (byte b : bytes) {
115            result.append(String.format("%02x", b));
116        }
117        return result.toString();
118    }
119
120    private static String getCanonicalURIPath(String path) {
121        if (path == null) {
122            return "/";
123        } else if (path.startsWith("/")) {
124            return normalizePath(path);
125        } else {
126            return "/" + normalizePath(path);
127        }
128    }
129
130    private static String normalize(String value) {
131        try {
132            StringBuilder builder = new StringBuilder();
133            for (byte b : value.getBytes(DEFAULT_ENCODING)) {
134                if (URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) {
135                    builder.append((char) b);
136                } else {
137                    builder.append(PERCENT_ENCODED_STRINGS[b & 0xFF]);
138                }
139            }
140            return builder.toString();
141        } catch (UnsupportedEncodingException e) {
142            throw new RuntimeException(e);
143        }
144    }
145
146    private static String normalizePath(String path) {
147        return normalize(path).replace("%2F", "/");
148    }
149
150
151    private static String getCanonicalQueryString(Map<String, String> parameters, boolean forSignature) {
152        if (parameters.isEmpty()) {
153            return "";
154        }
155
156        List<String> parameterStrings = new ArrayList<>();
157        for (Map.Entry<String, String> entry : parameters.entrySet()) {
158            if (forSignature && AUTHORIZATION.equalsIgnoreCase(entry.getKey())) {
159                continue;
160            }
161            String key = entry.getKey();
162            checkNotNull(key, "parameter key should not be null");
163            String value = entry.getValue();
164            if (value == null) {
165                if (forSignature) {
166                    parameterStrings.add(normalize(key) + '=');
167                } else {
168                    parameterStrings.add(normalize(key));
169                }
170            } else {
171                parameterStrings.add(normalize(key) + '=' + normalize(value));
172            }
173        }
174        Collections.sort(parameterStrings);
175
176        return String.join("&", parameterStrings);
177    }
178
179    private static <T> T checkNotNull(T reference, Object errorMessage) {
180        if (reference == null) {
181            throw new NullPointerException(String.valueOf(errorMessage));
182        } else {
183            return reference;
184        }
185    }
186
187    private static SortedMap<String, String> getHeadersToSign(Map<String, String> headers, Set<String> headersToSign) {
188        SortedMap<String, String> ret = new TreeMap<>();
189        if (headersToSign != null) {
190            Set<String> tempSet = new HashSet<>();
191            for (String header : headersToSign) {
192                tempSet.add(header.trim().toLowerCase());
193            }
194            headersToSign = tempSet;
195        }
196        for (Map.Entry<String, String> entry : headers.entrySet()) {
197            String key = entry.getKey();
198            if (entry.getValue() != null && !entry.getValue().isEmpty()) {
199                if ((headersToSign == null && isDefaultHeaderToSign(key))
200                        || (headersToSign != null && headersToSign.contains(key.toLowerCase())
201                        && !AUTHORIZATION.equalsIgnoreCase(key))) {
202                    ret.put(key, entry.getValue());
203                }
204            }
205        }
206        return ret;
207    }
208
209    private static boolean isDefaultHeaderToSign(String header) {
210        header = header.trim().toLowerCase();
211        return header.startsWith(BCE_PREFIX) || defaultHeadersToSign.contains(header);
212    }
213
214    private static String getCanonicalHeaders(SortedMap<String, String> headers) {
215        if (headers.isEmpty()) {
216            return "";
217        }
218
219        List<String> headerStrings = new ArrayList<>();
220        for (Map.Entry<String, String> entry : headers.entrySet()) {
221            String key = entry.getKey();
222            if (key == null) {
223                continue;
224            }
225            String value = entry.getValue();
226            if (value == null) {
227                value = "";
228            }
229            headerStrings.add(normalize(key.trim().toLowerCase()) + ':' + normalize(value.trim()));
230        }
231        Collections.sort(headerStrings);
232
233        return String.join("\n", headerStrings);
234    }
235
236}测试代码
                Java
                
            
            1import org.junit.Test;
2
3import java.io.BufferedReader;
4import java.io.DataOutputStream;
5import java.io.InputStreamReader;
6import java.net.HttpURLConnection;
7import java.net.URL;
8import java.util.HashMap;
9import java.util.Map;
10
11public class BaiduV1SignerTest {
12
13    @Test
14    public void postApiTest() throws Exception {
15
16        // todo: host
17        String host = "smarthome-bdvs.baidubce.com";
18
19
20        // todo: 请求地址
21        String uri = "/v1/dynamicDict/list";
22
23
24        // todo: 请求体
25        String requestBodyStr = "{\n" +
26                "  \"fc\": \"device_fc\",\n" +
27                "  \"pk\": \"device_pk\",\n" +
28                "  \"ak\": \"mock_ak01\",\n" +
29                "  \"normValue\": \"A01\",\n" +
30                "  \"synonymValue\": \"xxxx\"\n" +
31                "}";
32
33
34        String urls = "https://" + host + uri;
35        // 创建一个URL对象
36        URL url = new URL(urls);
37
38        Map<String, String> hashMap = new HashMap<>();
39        hashMap.put("Content-Type", "application/json");
40        hashMap.put("Host", host);
41
42        // 使用URL对象创建一个URLConnection对象
43        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
44        connection.setRequestMethod("POST");
45        connection.setRequestProperty("Content-Type", "application/json");
46        connection.setRequestProperty("Authorization", BaiduV1Singer.sign(uri, "POST", new HashMap<>(), hashMap));
47
48        // 发送POST请求必须设置如下两行
49        connection.setDoOutput(true);
50        connection.setDoInput(true);
51
52        // 获取输出流
53        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
54        out.writeBytes(requestBodyStr);
55        out.flush();
56        out.close();
57
58        // 从URLConnection对象获取输入流
59        BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
60
61        String inputLine;
62        while ((inputLine = in.readLine()) != null)
63            System.out.println(inputLine);
64        in.close();
65    }
66
67}AWS版本
核心代码
                Java
                
            
            1import javax.crypto.Mac;
2import javax.crypto.spec.SecretKeySpec;
3import java.net.HttpURLConnection;
4import java.net.URI;~~~~
5import java.net.URISyntaxException;
6import java.nio.charset.StandardCharsets;
7import java.security.MessageDigest;
8import java.security.NoSuchAlgorithmException;
9import java.time.LocalDateTime;
10import java.time.ZoneId;
11import java.time.format.DateTimeFormatter;
12
13public class BaiduUrlConnectionSigner {
14
15    private static final String ACCESS_KEY = "your_ak";
16    private static final String SECRET_KEY = "your_sk";
17
18
19    private static final String CONTENT_TYPE = "application/json";
20
21    /**
22     * 固定值
23     */
24    private static final String REGION = "us-east-1";
25
26    /**
27     * 固定值
28     */
29    private static final String SERVICE = "execute-api";
30
31
32    /**
33     * 生成带有签名的请求
34     *
35     * @param connection  需要签名的请求
36     * @param requestBody 请求体
37     * @return 带有签名的请求
38     * @throws Exception 签名过程中可能发生的异常
39     */
40    public static void getSignedRequest(HttpURLConnection connection, String requestBody) throws Exception {
41        String format = getAuthDate();
42        String authorizationHeader = getAuthorizationHeader(connection.getURL().toString(), connection.getRequestMethod(), requestBody,
43                format);
44        connection.setRequestProperty("Content-Type", CONTENT_TYPE);
45        connection.setRequestProperty("Authorization", authorizationHeader);
46        connection.setRequestProperty("X-Amz-Content-Sha256", calculateSHA256(requestBody));
47        connection.setRequestProperty("X-Amz-Date", format);
48    }
49
50
51    private static String getAuthDate() {
52        return LocalDateTime.now(ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
53    }
54
55    public static String getAuthorizationHeader(String url, String method, String requestBody, String amzDate) throws Exception {
56
57        URI uri;
58        try {
59            uri = new URI(url);
60        } catch (URISyntaxException e) {
61            throw new Exception("Invalid URL: " + url);
62        }
63        String host = uri.getAuthority();
64        String canonicalUri = uri.getPath();
65        String canonicalQuerystring = uri.getQuery();
66        String contentHash = calculateSHA256(requestBody);
67
68        String canonicalHeaders = "content-type:" + CONTENT_TYPE + "\n" +
69                "host:" + host + "\n" +
70                "x-amz-content-sha256:" + contentHash + "\n" +
71                "x-amz-date:" + amzDate + "\n";
72
73        String signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";
74        String canonicalRequest = method + "\n" + canonicalUri + "\n" + (canonicalQuerystring == null ? "" : canonicalQuerystring) + "\n" +
75                canonicalHeaders + "\n" + signedHeaders + "\n" + contentHash;
76        String credentialScope = amzDate.substring(0, 8) + "/" + REGION + "/" + SERVICE + "/aws4_request";
77        String stringToSign = "AWS4-HMAC-SHA256\n" + amzDate + "\n" + credentialScope + "\n" +
78                calculateSHA256(canonicalRequest);
79
80        byte[] signingKey = getSigningKey(amzDate.substring(0, 8));
81        String signature = calculateHMAC(stringToSign, signingKey);
82
83        return "AWS4-HMAC-SHA256 Credential=" + ACCESS_KEY + "/" + credentialScope + ", " +
84                "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
85    }
86
87    private static String calculateSHA256(String text) throws NoSuchAlgorithmException {
88        MessageDigest digest = MessageDigest.getInstance("SHA-256");
89        byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
90        return bytesToHex(hash);
91    }
92
93    private static String bytesToHex(byte[] bytes) {
94        StringBuilder result = new StringBuilder();
95        for (byte b : bytes) {
96            result.append(String.format("%02x", b));
97        }
98        return result.toString();
99    }
100
101    private static byte[] getSigningKey(String dateStamp) throws Exception {
102        byte[] kSecret = ("AWS4" + SECRET_KEY).getBytes(StandardCharsets.UTF_8);
103        byte[] kDate = hmacSHA256(dateStamp, kSecret);
104        byte[] kRegion = hmacSHA256(REGION, kDate);
105        byte[] kService = hmacSHA256(SERVICE, kRegion);
106        return hmacSHA256("aws4_request", kService);
107    }
108
109    private static byte[] hmacSHA256(String data, byte[] key) throws Exception {
110        Mac mac = Mac.getInstance("HmacSHA256");
111        SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA256");
112        mac.init(keySpec);
113        return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
114    }
115
116    private static String calculateHMAC(String data, byte[] key) throws Exception {
117        byte[] hmacData = hmacSHA256(data, key);
118        return bytesToHex(hmacData);
119    }
120
121
122}测试代码
                Java
                
            
            1import org.junit.Test;
2
3import java.io.BufferedReader;
4import java.io.DataOutputStream;
5import java.io.InputStreamReader;
6import java.net.HttpURLConnection;
7import java.net.URL;
8
9public class URLConnectionSignerTest {
10
11    @Test
12    public void postApiTest() throws Exception {
13
14        // todo: 请求地址
15        String urls = "http://smarthome-bdvs.baidubce.com/v1/dynamicDict/list";
16
17        // todo: 请求体
18        String requestBodyStr = "{\n" +
19                "  \"fc\": \"device_fc\",\n" +
20                "  \"pk\": \"device_pk\",\n" +
21                "  \"ak\": \"mock_ak01\",\n" +
22                "  \"normValue\": \"A01\",\n" +
23                "  \"synonymValue\": \"xxxx\"\n" +
24                "}";
25
26        // 创建一个URL对象
27        URL url = new URL(urls);
28
29        // 使用URL对象创建一个URLConnection对象
30        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
31        connection.setRequestMethod("POST");
32
33        // 设置请求签名。
34        BaiduUrlConnectionSigner.getSignedRequest(connection, requestBodyStr);
35
36        // 发送POST请求必须设置如下两行
37        connection.setDoOutput(true);
38        connection.setDoInput(true);
39
40        // 获取输出流
41        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
42        out.writeBytes(requestBodyStr);
43        out.flush();
44        out.close();
45
46        // 从URLConnection对象获取输入流
47        BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
48
49        String inputLine;
50        while ((inputLine = in.readLine()) != null)
51            System.out.println(inputLine);
52        in.close();
53    }
54
55}