前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kong网关hmac-auth认证插件配置指引,附几种语言的客户端实现

Kong网关hmac-auth认证插件配置指引,附几种语言的客户端实现

作者头像
windealli
发布2023-10-13 11:29:48
7180
发布2023-10-13 11:29:48
举报
文章被收录于专栏:windealli

使用Kong网关hmac-auth插件进行接口鉴权

Kong网关配置

1. 为需要鉴权的route或者service天假hmac-auth插件

请在此添加图片描述

请在此添加图片描述

2. 为调用方创建ConsumerCredentials

请在此添加图片描述

请在此添加图片描述

客户端签名生成

签名算法参考

使用 HMAC Auth 认证访问

ApiFox中的JavaScript前置脚本实现

hmacUsernamehmacSecret 需要传入Kong网关Consumer中配置的值

代码语言:javascript
复制
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})

Golang 实现

generateKongHmacSHA256Signature()的参数需要传入Kong网关Consumer中配置的值

代码语言:javascript
复制
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))
}

Java实现

代码语言:javascript
复制
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;
    }
}
测试用例
代码语言:javascript
复制
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);
    }

}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-09-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 海天二路搬砖工 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用Kong网关hmac-auth插件进行接口鉴权
    • Kong网关配置
      • 1. 为需要鉴权的route或者service天假hmac-auth插件
      • 2. 为调用方创建Consumer和Credentials
    • 客户端签名生成
      • 签名算法参考
      • ApiFox中的JavaScript前置脚本实现
      • Golang 实现
      • Java实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档