跳到主要内容
版本:3.10.x

在访问日志中包含消费者标签

API7 网关可以把消费者标签写入访问日志。以下示例将 company 标签写入自定义 $consumer_company 变量,然后在访问日志中输出该变量。

工作原理

流程包括:声明 NGINX 自定义变量、将变量加入访问日志格式、使用 Serverless Function 为变量赋值,以及配置消费者和受保护路由。

前置条件

步骤一:声明自定义变量

在数据面 conf/config.yaml 中初始化变量并设置默认值 -

conf/config.yaml
nginx_config:
http_server_location_configuration_snippet: |
set $consumer_company "-";

步骤二:更新访问日志格式

将变量加入访问日志格式:

conf/config.yaml
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 标签:

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"
]
}
}
}'

插件会读取消费者的 company 标签。如果消费者没有该标签,或请求没有识别出消费者(例如未认证请求),变量值默认为 unknown

步骤四:配置消费者和受保护路由

创建带有 company: smart-technology 标签的消费者 john,为其配置 Key Authentication 凭据 john-key,再创建一个受 key-auth 保护的路由。

# 创建带标签的消费者
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": {}
}
}'

为路由启用 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-loggerkafka-logger 等日志插件记录标签,可以使用 attach-consumer-label 将消费者标签映射为上游请求标头。以下示例在同一路由上同时启用 key-authattach-consumer-labelhttp-logger

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"
}
}
}
}'

attach-consumer-label 中的 $ 前缀引用消费者标签键。已认证消费者的对应标头会在请求到达上游和日志插件前注入。

其他资源