route
或者service
天假hmac-auth
插件请在此添加图片描述
请在此添加图片描述
Consumer
和Credentials
请在此添加图片描述
请在此添加图片描述
使用 HMAC Auth 认证访问
hmacUsername
和 hmacSecret
需要传入Kong网关Consumer
中配置的值
hmacUsername = pm.environment.get("hmac_username"); // 替换成业务真实值
hmacSecret = pm.environment.get("hmac_secret"); // 替换成业务真实值
console.log("hmacUsername:" + hmacUsername + ", hmacSecret:" + hmacSecret)
var curDate = new Date().toUTCString() // 获取当前时间
// 生成请求body的摘要
var digest = CryptoJS.SHA256(request.data) // 生成body摘要
digest = "SHA-256=" + CryptoJS.enc.Base64.stringify(digest)
console.log(curDate)
console.log("SHA-256摘要为: " + digest);
// 计算签名
var strToSign = `x-date: ${curDate}\ndigest: ${digest}`
console.log("用于计算签名的字符串: " + strToSign)
const hash = CryptoJS.HmacSHA256(strToSign, hmacSecret);
const hashString = CryptoJS.enc.Base64.stringify(hash);
auth = `hmac username="${hmacUsername}", algorithm="hmac-sha256", headers="x-date digest", signature="${hashString}"`
console.log("签名: " + auth)
// 按顺序添加header
pm.request.headers.add({key:'x-date', value:curDate})
pm.request.headers.add({key:'digest', value:digest})
pm.request.headers.add({key:'Authorization', value:auth})
generateKongHmacSHA256Signature()
的参数需要传入Kong网关Consumer
中配置的值
package main
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
)
const url = "https://dev-cms.ssv.qq.com/kratosLayoutWebAPI/demo/v1/sayHello"
func generateKongHmacSHA256Signature(
ctx context.Context,
hmacUsername, hmacSecret string,
body []byte) (
xDate, digest, authorization string) {
//hmacKey := []byte(hmacSecret)
xDate = time.Now().UTC().Format(time.RFC1123)
// 生成请求摘要
h := sha256.Sum256(body) // 计算 SHA256 摘要
digest = "SHA-256=" + base64.StdEncoding.EncodeToString(h[:])
fmt.Println(xDate, digest)
// 计算签名
hMac := hmac.New(sha256.New, []byte(hmacSecret))
strToSign := fmt.Sprintf("x-date: %s\ndigest: %s", xDate, digest)
hMac.Write([]byte(strToSign))
sig := hMac.Sum(nil)
hashString := base64.StdEncoding.EncodeToString(sig)
// 生成鉴权头
authorization = fmt.Sprintf(`hmac username="%s", algorithm="hmac-sha256", headers="x-date digest", signature="%s"`,
hmacUsername, hashString)
// 输出结果
fmt.Println("用于计算签名的字符串: " + strToSign)
fmt.Println("签名: " + authorization)
return xDate, digest, authorization
}
func main() {
reqBody := struct {
RequestId string
Name string
}{
RequestId: "2023-07-20-001",
Name: "windeal",
}
bReqBody, _ := json.Marshal(reqBody)
xDate, digest, authorization := generateKongHmacSHA256Signature(
context.Background(), "xxxxx", "xxxxx", bReqBody)
payload := strings.NewReader(`{"RequestId":"2023-07-20-001","Name":"windeal"}`)
client := &http.Client{}
req, err := http.NewRequest(http.MethodPost, url, payload)
// 按*顺序*添加请求头
req.Header.Add("content-type", "application/json")
req.Header.Add("x-Date", xDate)
req.Header.Add("digest", digest)
req.Header.Add("authorization", authorization)
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
bRspBody, err := io.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(bRspBody))
}
package cn.lipeilun.kong.auth;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.MessageDigest;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
public class KongHmacAuthClient {
private final String baseUrl;
private final String hmacUsername;
private final String hmacSecret;
public KongHmacAuthClient(String baseUrl, String hmacUsername, String hmacSecret) {
this.baseUrl = baseUrl;
this.hmacUsername = hmacUsername;
this.hmacSecret = hmacSecret;
}
public String callKongHMACAPI(String path, String method, ContentType contentType, Header[] headers, String requestBody)
throws NoSuchAlgorithmException, InvalidKeyException, IOException {
Map<String, String> authHeaders = generateAuthHeaders(requestBody);
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(this.baseUrl + path);
for (Header header : headers) {
httpPost.addHeader(header);
}
// 按顺序添加验签用的header
httpPost.addHeader("x-date", authHeaders.get("x-date"));
httpPost.addHeader("digest", authHeaders.get("digest"));
httpPost.addHeader("authorization", authHeaders.get("authorization"));
StringEntity params = new StringEntity(requestBody, contentType);
httpPost.setEntity(params);
System.out.println(Arrays.toString(httpPost.getAllHeaders()));
// 发送请求并获取响应
HttpEntity responseEntity = httpClient.execute(httpPost).getEntity();
// 将响应体转换为字符串
String response = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
System.out.println(response);
return response;
}
private Map<String, String> generateAuthHeaders(String requestBody)
throws NoSuchAlgorithmException, InvalidKeyException {
ZoneId gmt = ZoneId.of("GMT");
String xDate = ZonedDateTime.now(gmt).format(DateTimeFormatter.RFC_1123_DATE_TIME);
// String xDate = Instant.now().toString();
// 计算请求摘要
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] digestBytes = md.digest(requestBody.getBytes(StandardCharsets.UTF_8));
String digest = "SHA-256=" + Base64.getEncoder().encodeToString(digestBytes);
// 计算签名
String strToSign = String.format("x-date: %s\ndigest: %s", xDate, digest);
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec =
new SecretKeySpec(hmacSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKeySpec);
byte[] signatureBytes = mac.doFinal(strToSign.getBytes(StandardCharsets.UTF_8));
String signature = Base64.getEncoder().encodeToString(signatureBytes);
// 生成鉴权头
String authorization = String.format(
"hmac username=\"%s\", algorithm=\"hmac-sha256\", headers=\"x-date digest\", signature=\"%s\"",
hmacUsername, signature);
Map<String, String> authHeaders = new HashMap<>();
authHeaders.put("x-date", xDate);
authHeaders.put("digest", digest);
authHeaders.put("authorization", authorization);
return authHeaders;
}
}
package cn.lipeilun.kong.auth;
import org.apache.http.Header;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.junit.Test;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class KongHmacAuthClientTest {
@Test
public void testCallAPI() throws NoSuchAlgorithmException, IOException, InvalidKeyException {
KongHmacAuthClient client = new KongHmacAuthClient(
"https://dev-cms.ssv.qq.com", "请替换真实的username", "请替换真实的Secret");
String path = "/kratosLayoutWebAPI/demo/v1/sayHello";
ContentType contentType = ContentType.APPLICATION_JSON;
String requestBody = "{\"RequestId\":\"2023-08-17-001\",\"Name\":\"windeal\"}";
Header[] headers = new Header[0];
String response = client.callKongHMACAPI(path, "POST", contentType, headers, requestBody);
System.out.println(response);
}
}