有奖捉虫:办公协同&微信生态&物联网文档专题 HOT

操作场景

本文介绍如何在 Kong 云原生 API 网关上通过 HMAC Authentication 认证插件实现认证访问。

前置条件

已购买 Kong 网关实例,操作文档
配置了后端(Service)以及路由(Route)。

操作步骤

本场景操作步骤以配置 Route 插件为例,指导如何实现 HMac Auth 认证访问。

步骤1:配置 HMAC Authentication 认证插件

1. 登录 TSE 控制台,进入需要配置限流插件的 Kong 网关实例详情页,在 Konga 控制台页面查看管理控制台登录方式。



2. 登录 Konga 管理控制台,进入需要限流的 Route 详情页,单击 Add Plugin 按钮创建插件,在 Authentication 分组下选择 Hmac Auth 插件。



3. 设置密钥身份认证插件参数,单击 enter 键,并保存。
consumer:填写需要应用访问控制的 Consumer ID,如空缺,表示该 IP 访问控制应用于所有 consumer。
hide credentials:是否隐藏来自上游服务的凭据。
anonymous:如果身份验证失败,则用作“匿名”使用者的可选字符串(使用者 uuid)值。如果为空(默认),则请求将失败,并且身份验证失败4xx。 请注意,此值必须引用 Kong 内部的 Consumer id 属性,而不是其 custom_id。
clock skew:时钟偏移在几秒钟内以防止重放攻击。
validate request body:是否启用 body 验证。
enforce headers:客户端至少应用于 HTTP 签名创建的 header 列表。
algorithms:用户想要支持的 HMAC 摘要算法列表。允许的值为 hmac-sha1,hmac-sha256,hmac-sha384 和 hmac-sha512,默认全部支持。




步骤2:创建 Consumer

1. 进入 CONSUMERS 页面创建 Consumer。



username:用户(应用)名,必须指定此字段或 custom_id。
custom_id:用于将使用者映射到另一个数据库的自定义标识符。必须指定此字段或 username。
Tags:标签。



2. 为 Consumer 创建 HMAC Auth 凭证。



username:在 HMAC 签名验证中使用的用户名。
secret:secret 值,默认为空会自动生成 secret。




步骤3:签名认证方案

期望客户端使用以下参数化发送 Authorization 或 Proxy-Authorization header:
例如: Authorization: hmac username="username", algorithm="hmac-sha1", headers="x-date digest", signature="Base64(HMAC-SHA1(signing_str, secret))"

签名参数

username:凭证的 username。
algorithm:用于创建签名的数字签名算法。
headers:用于对请求进行签名的 HTTP 标头名称列表,由单个空格字符分隔。
signature:客户端生成的 Base64 编码数字签名。

签名字符串构造

为了生成使用密钥签名的字符串,客户端必须按照它们出现的顺序获取 headers 指定的每个 HTTP 标头的值。
1. 如果标题名称不是 request-line,则附加小写标题名称,后跟 ASCII 冒号:和 ASCII 空格 。
2. 如果标题名称是 request-line,则附加 HTTP 请求行(ASCII 格式),否则追加标题值。
3. 如果 value 不是最后一个值,则附加 ASCII 换行符\\n。字符串绝不能包含尾随的 ASCII 换行符。
4. 服务器和请求客户端应与 NTP 同步,并且应使用 X-Date 或 Date header 发送有效日期(使用 GMT 格式, 例如 Mon, 19 Mar 2018 12:08:40 GMT)。

正文验证 Body Validation

用户可以将 config.validate_request_body 设置为 true 以验证请求正文。如果启用,插件将计算请求正文的 SHA-256 HMAC 摘要,并将其与 Digest header 的值进行匹配。 摘要 header 需要采用以下格式: Digest: SHA-256=base64(sha256(<body>))
如果没有请求主体,则应将 Digest 设置为0长度的主体的摘要。
注意
为了创建请求主体的摘要,插件需要将其保留在内存中,这可能会在处理大型主体(几个MB)或高请求并发期间对工作者的 Lua VM 造成压力。

步骤4:API 请求 Demo

# -*- coding: utf-8 -*-
import base64
import datetime
import hashlib
import hmac
import json
import requests
from urllib.parse import urlparse, urlencode

#username
Username = 'xxx'
#secret
Secret = 'xxxx'

# 访问地址
Url = 'http://test.com/'
HTTPMethod = 'POST' # method
Accept = 'application/json'
ContentType = 'application/json'

urlInfo = urlparse(Url)
Host = urlInfo.hostname
Path = urlInfo.path

Digest = ''
GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
xDate = datetime.datetime.utcnow().strftime(GMT_FORMAT)

# 修改 body 内容
if HTTPMethod == 'POST' :
body = { "arg1": "a", "arg2": "中文" }
body_json = json.dumps(urlencode(body))
body_digest = hashlib.sha256(body_json.encode()).digest()
Digest = "SHA-256=" + base64.b64encode(body_digest).decode()
print(Digest)

# 获取签名串
signing_str = 'x-date: %s\\ndigest: %s' % (
xDate, Digest)

# 计算签名
sign = hmac.new(Secret.encode(), msg=signing_str.encode(), digestmod=hashlib.sha1).digest()
sign = base64.b64encode(sign).decode()
auth = "hmac username=\\"" + Username + "\\", algorithm=\\"hmac-sha1\\", headers=\\"x-date digest\\", signature=\\""
sign = auth + sign + "\\""

# 发送请求
headers = {
'Host': Host,
'Accept': Accept,
'Content-Type': ContentType,
'x-date': xDate,
'Authorization': sign
}

if Digest :
headers['Digest'] = Digest

if HTTPMethod == 'GET' :
ret = requests.get(Url, headers=headers)
if HTTPMethod == 'POST' :
ret = requests.post(Url, headers=headers, data=(body_json))

print(ret.headers)
print(ret.text)


相关说明

更多相关说明请参见 Kong 插件