在访问日志中包含消费者标签
API7 网关可以把消费者标签写入访问日志。以下示例将 company 标签写入自定义 $consumer_company 变量,然后在访问日志中输出该变量。
工作原理
流程包括:声明 NGINX 自定义变量、将变量加入访问日志格式、使用 Serverless Function 为变量赋值,以及配置消费者和受保护路由。
前置条件
步骤一:声明自定义变量
在数据面 conf/config.yaml 中初始化变量并设置默认值 -:
nginx_config:
http_server_location_configuration_snippet: |
set $consumer_company "-";
步骤二:更新访问日志格式
将变量加入访问日志格式:
nginx_config:
http:
access_log_format: '$remote_addr - $remote_user [$time_local] $http_host "$request_line" $status $body_bytes_sent $request_time "$http_referer" "$http_user_agent" $upstream_addr $upstream_status $upstream_response_time "$apisix_request_id" "$consumer_company"'
重新加载或重启网关使配置生效。
步骤三:使用 Serverless Function 赋值
使用 serverless-pre-function 在 rewrite 阶段为变量赋值。该示例读取消费者的 company 标签:
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/global_rules/serverless-pre-function?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"plugins": {
"serverless-pre-function": {
"phase": "rewrite",
"functions": [
"return function (conf, ctx) ngx.var.consumer_company = ctx.consumer and ctx.consumer.labels and ctx.consumer.labels[\"company\"] or \"unknown\" end"
]
}
}
}'
global_rules:
serverless-pre-function:
phase: rewrite
functions:
- >-
return function (conf, ctx)
ngx.var.consumer_company = ctx.consumer
and ctx.consumer.labels
and ctx.consumer.labels["company"]
or "unknown"
end
adc sync -f adc.yaml
插件会读取消费者的 company 标签。如果消费者没有该标签,或请求没有识别出消费者(例如未认证请求),变量值默认为 unknown。
步骤四:配置消费者和受保护路由
创建带有 company: smart-technology 标签的消费者 john,为其配置 Key Authentication 凭据 john-key,再创建一个受 key-auth 保护的路由。
- Admin API
- ADC
# 创建带标签的消费者
curl -k "https://localhost:7443/apisix/admin/consumers/john?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"username": "john",
"labels": {
"company": "smart-technology"
}
}'
# 添加 key-auth 凭据
curl -k "https://localhost:7443/apisix/admin/consumers/john/credentials/primary-key?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "primary-key",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
# 创建带上游的 Service
curl -k "https://localhost:7443/apisix/admin/services/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "consumer-label-demo",
"upstream": {
"type": "roundrobin",
"nodes": [
{ "host": "httpbin.org", "port": 80, "weight": 1 }
]
}
}'
# 创建受 key-auth 保护的路由
curl -k "https://localhost:7443/apisix/admin/routes/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "consumer-label-demo",
"paths": ["/anything"],
"service_id": "consumer-label-demo",
"plugins": {
"key-auth": {}
}
}'
consumers:
- username: john
labels:
company: smart-technology
credentials:
- name: primary-key
type: key-auth
config:
key: john-key
services:
- name: consumer-label-demo
routes:
- name: consumer-label-demo
uris:
- /anything
plugins:
key-auth: {}
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
adc sync -f adc.yaml
为路由启用 key-auth 后,使用有效密钥发送请求:
curl -i "http://127.0.0.1:9080/anything" -H 'apikey: john-key'
访问日志中应看到 smart-technology。不带密钥发送请求:
curl -i "http://127.0.0.1:9080/anything"
请求应返回 401 Unauthorized,访问日志中的标签值应为 unknown。
步骤五:验证
检查访问日志,确认每个请求末尾包含消费者标签。对于认证请求,日志应显示 smart-technology;对于未认证请求,日志应显示 unknown。
替代方案:通过标头转发标签
如果下游服务需要直接读取标签,可以在 Serverless Function 中设置请求标头,例如 X-Consumer-Company,然后让上游服务读取该标头。请注意,只有在信任网关并确保客户端无法伪造该标头时,才应采用这种方式。
如果要让 http-logger 或 kafka-logger 等日志插件记录标签,可以使用 attach-consumer-label 将消费者标签映射为上游请求标头。以下示例在同一路由上同时启用 key-auth、attach-consumer-label 和 http-logger:
- Admin API
- ADC
curl -k "https://localhost:7443/apisix/admin/routes/consumer-label-demo?gateway_group_id={gateway_group_id}" -X PUT \
-H "X-API-KEY: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "consumer-label-demo",
"paths": ["/anything"],
"service_id": "consumer-label-demo",
"plugins": {
"key-auth": {},
"attach-consumer-label": {
"headers": {
"X-Consumer-Company": "$company"
}
},
"http-logger": {
"uri": "http://log-collector:8080/logs",
"log_format": {
"consumer_company": "$http_x_consumer_company"
}
}
}
}'
services:
- name: consumer-label-demo
routes:
- name: consumer-label-demo
uris:
- /anything
plugins:
key-auth: {}
attach-consumer-label:
headers:
X-Consumer-Company: "$company"
http-logger:
uri: http://log-collector:8080/logs
log_format:
consumer_company: "$http_x_consumer_company"
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
adc sync -f adc.yaml
attach-consumer-label 中的 $ 前缀引用消费者标签键。已认证消费者的对应标头会在请求到达上游和日志插件前注入。