From e54e57436b6f9cb36768a36da4b2dfc4b6cf1817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chu=20V=C4=83n=20H=E1=BA=A3i?= Date: Thu, 18 Jun 2026 10:58:08 +0700 Subject: [PATCH] update apisix_conf --- apisix-stack/README.MD | 16 +++++++++++----- apisix-stack/apisix_conf/config.yaml | 4 ++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/apisix-stack/README.MD b/apisix-stack/README.MD index b14f82f..4124ea5 100644 --- a/apisix-stack/README.MD +++ b/apisix-stack/README.MD @@ -123,8 +123,8 @@ Phương án này cho phép **Client** chỉ cần truyền API Key đơn giản ```yaml nginx_config: - custom_lua_shared_dict: - oauth_cache: 1m # Cấp 1MB bộ nhớ để cache access token + http_configuration_snippet: | + lua_shared_dict oauth_cache 1m; # Cấp 1MB bộ nhớ để cache access token ``` #### Bước 2: Thiết lập Route với plugin `key-auth` và `serverless-pre-function` @@ -140,13 +140,19 @@ curl -i http://localhost:9180/apisix/admin/routes/ssm-vn-dev-route \ "name": "ssm-vn-dev-route", "plugins": { "key-auth": {}, + "proxy-rewrite": { + "regex_uri": [ + "^/ssm-vn-dev(/.*)$", + "$1" + ] + }, "serverless-pre-function": { "phase": "access", "functions": [ - "return function(conf, ctx) local core = require(\"apisix.core\"); local http = require(\"resty.http\"); local cache = ngx.shared.oauth_cache; if not cache then core.log.error(\"oauth_cache not defined in config.yaml\"); return end; local token = cache:get(\"dataverse_token\"); if not token then local httpc = http.new(); httpc:set_timeout(5000); local tenant_id = \"\"; local client_id = \"\"; local client_secret = \"\"; local scope = \"https://.crm.dynamics.com/.default\"; local body = \"grant_type=client_credentials&client_id=\" .. ngx.escape_uri(client_id) .. \"&client_secret=\" .. ngx.escape_uri(client_secret) .. \"&scope=\" .. ngx.escape_uri(scope); local res, err = httpc:request_uri(\"https://login.microsoftonline.com/\" .. tenant_id .. \"/oauth2/v2.0/token\", { method = \"POST\", body = body, headers = { [\"Content-Type\"] = \"application/x-www-form-urlencoded\" }, ssl_verify = false }); if not res or res.status ~= 200 then core.log.error(\"Failed to fetch Azure AD token: \", err or (res and res.body)); return core.response.exit(500, { error = \"Auth failed to upstream provider\" }) end; local data, decode_err = core.json.decode(res.body); if not data or not data.access_token then core.log.error(\"Failed to decode token response\"); return core.response.exit(500, { error = \"Invalid token response\" }) end; token = data.access_token; local expires_in = data.expires_in or 3600; cache:set(\"dataverse_token\", token, expires_in - 60) end; ngx.req.set_header(\"Authorization\", \"Bearer \" .. token) end" + "return function(conf, ctx) local core = require(\"apisix.core\"); local http = require(\"resty.http\"); local cache = ngx.shared.oauth_cache; if not cache then core.log.error(\"oauth_cache not defined in config.yaml\"); return end; local token = cache:get(\"dataverse_token_ssm_vn_dev\"); if not token then local httpc = http.new(); httpc:set_timeout(5000); local tenant_id = \"2081a403-c773-427a-86a4-543f0983d921\"; local client_id = \"2f680fb4-35b8-4be2-99ee-a3d183b607c9\"; local client_secret = \"l9k8Q~7hqvzxohEkGftZ4rPBYaq6JF68wNLwKb1N\"; local scope = \"https://tngredev.crm5.dynamics.com/.default\"; local body = \"grant_type=client_credentials&client_id=\" .. ngx.escape_uri(client_id) .. \"&client_secret=\" .. ngx.escape_uri(client_secret) .. \"&scope=\" .. ngx.escape_uri(scope); local res, err = httpc:request_uri(\"https://login.microsoftonline.com/\" .. tenant_id .. \"/oauth2/v2.0/token\", { method = \"POST\", body = body, headers = { [\"Content-Type\"] = \"application/x-www-form-urlencoded\" }, ssl_verify = false }); if not res or res.status ~= 200 then core.log.error(\"Failed to fetch Azure AD token: \", err or (res and res.body)); return core.response.exit(500, { error = \"Auth failed to upstream provider\" }) end; local data, decode_err = core.json.decode(res.body); if not data or not data.access_token then core.log.error(\"Failed to decode token response\"); return core.response.exit(500, { error = \"Invalid token response\" }) end; token = data.access_token; local expires_in = data.expires_in or 3600; cache:set(\"dataverse_token_ssm_vn_dev\", token, expires_in - 60) end; ngx.req.set_header(\"Authorization\", \"Bearer \" .. token) end" ] }, - "rate-limiting": { + "limit-count": { "count": 100, "time_window": 60, "rejected_code": 429 @@ -166,6 +172,7 @@ curl -i http://localhost:9180/apisix/admin/routes/ssm-vn-dev-route \ > [!IMPORTANT] > **Giải thích tham số cấu hình Upstream:** > * `pass_host: "node"`: Bắt buộc cấu hình trường này để APISIX ghi đè giá trị header `Host` gửi tới Dynamics 365 trùng khớp với node URL (`.crm.dynamics.com`). Nếu thiếu, Dynamics 365 sẽ từ chối xử lý request vì host header không khớp. +> * `proxy-rewrite.regex_uri`: Bắt buộc để bỏ prefix route nội bộ `/ssm-vn-dev` trước khi gọi Dataverse. Request vào `/ssm-vn-dev/api/data/v9.0/...` sẽ được gửi lên upstream thành `/api/data/v9.0/...`. > * Các tham số ``, ``, ``, `` trong đoạn mã Lua cần được thay thế bằng thông tin môi trường Azure AD và Dynamics 365 thực tế của bạn. #### Chi tiết kịch bản script Lua chạy trong APISIX: @@ -245,4 +252,3 @@ curl -i http://localhost:9180/apisix/admin/global_rules/1 \ 5. Click vào bất kỳ dòng log nào bên dưới kết quả. Bạn sẽ thấy các trường dữ liệu được phân tích cấu trúc, bao gồm: - `request.body`: Chứa toàn bộ nội dung Request payload từ Client. - `response.body` hoặc `resp_body`: Chứa toàn bộ nội dung Response payload trả về từ phía Dataverse. - diff --git a/apisix-stack/apisix_conf/config.yaml b/apisix-stack/apisix_conf/config.yaml index e0ab4a1..244d309 100644 --- a/apisix-stack/apisix_conf/config.yaml +++ b/apisix-stack/apisix_conf/config.yaml @@ -18,8 +18,8 @@ deployment: prefix: "/apisix" nginx_config: - custom_lua_shared_dict: - oauth_cache: 1m + http_configuration_snippet: | + lua_shared_dict oauth_cache 1m; http: access_log: "/dev/stdout" access_log_format: '{"time_local":"$time_local","client_ip":"$remote_addr","request":"$request","status":$status,"body_bytes_sent":$body_bytes_sent,"request_time":$request_time,"upstream_response_time":"$upstream_response_time"}'