[NGINX-Demo] Demo-4: A/B Testing with JWT.
อ้างอิงจาก บทความก่อนหน้า
4.1) ทำการแก้ไขไฟล์ docker-compose.yml ดังนี้
version: "3.7"
services:
nginx:
image: nginx-plus:latest
restart: always
ports:
- 80:80
volumes:
- ./conf/ab-testing-with-jwt-routing.conf:/etc/nginx/nginx.conf
- ./conf/api_secret.jwk:/etc/nginx/api_secret.jwk
จากสั่ง run ก็ใช้คำสั่ง
docker-compose up -d
ถ้าอยากดู logs แบบ realtime ของ nginx บน container ใช้คำสั่ง
docker-compose logs -f
4.2) ในการทดสอบนี้จะอ้างอิง nginx configuration จากไฟล์ ab-testing-with-jwt-routing.conf นี้
# JWT validation
auth_jwt "JWT Test Realm" token=$arg_myjwt;
auth_jwt_key_file /etc/nginx/api_secret.jwk;
และมีไฟล์ api_secret.jwt
{"keys":
[{
"k":"bmdpbngxMjM",
"kty":"oct"
}]
}
กำหนดค่า k คือ
symmetric key
เป็นnginx123
โดย encode ด้วย base64 จากคำสั่งนี้
echo -n nginx123 | base64 | tr '+/' '-_' | tr -d '='
4.3) ทำการสร้าง jwt token แบบง่ายๆ โดยไปที่เว็บ https://jwt.io โดยกำหนดรายละเอียดดังนี้
Header:
{
"alg": "HS256",
"typ": "JWT"
}
Payload:
{
"exp": 1659812957,
"name": "Create New User",
"sub": "cuser",
"gname": "wheel",
"guid": "10",
"fullName": "John Doe",
"uname": "jdoe",
"uid": "111",
"sudo": true,
"dept": "IT",
"url": "http://secure.example.com"
}
Verify Signature:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),nginx123
)
ตัวอย่าง ที่ใช้ทดสอบ จะกำหนด "uid":"111"
และ "uid":"222"
ดังนี้
4.4) ทดสอบเรียกโดย uid = 111
ส่ง jwt token ผ่านทาง myjwt
บน URI
curl -i http://localhost/\?myjwt\=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTk4MTI5NTcsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.WAKIXeopm8TVeDSMiDi3M1CY-4l4cvZZO5iIlzayBP4
ทดสอบเรียกโดย โดย uid = 222
ส่ง jwt token ผ่านทาง myjwt
บน URI
curl -i http://localhost/?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTk4MTI5NTcsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.j3kaqRXkbkJrCqTlWw0iKxlcgUVR_z3f5CLTaWPPS3M
4.5) ลองทำการส่ง jwt token ผ่านทาง Cookie กัน ลองเปลี่ยนตรง token
จาก $arg_myjwt
เป็น $cookie_myjwt
# JWT validation# auth_jwt "JWT Test Realm" token=$arg_myjwt;
auth_jwt "JWT Test Realm" token=$cookie_myjwt;
auth_jwt_key_file /etc/nginx/api_secret.jwk;
และทดสอบเรียกด้วย Cookie ดูครับ
curl -v --cookie myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTk4MTI5NTcsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.WAKIXeopm8TVeDSMiDi3M1CY-4l4cvZZO5iIlzayBP4 http://localhost
ถึงตรงนี้ ถือว่า เสร็จสิ้น การทดสอบเรื่อง A/B Testing ด้วย jwt ครับ
ส่งท้ายด้วย ในโหมด แอบซน และสงสัย****
0.1) ลองแกล้ง เปลี่ยนตัวอักษรบางตัว payload
ของ jwt token ดูว่า NGINX สามารถตรวจสอบ หรือ Validate JWT Authentication ได้จริงไหม ?
curl -i http://localhost/?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTk4MTI5NTcsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ0.j3kaqRXkbkJrCqTlWw0iKxlcgUVR_z3f5CLTaWPPS3M
หมายเหตุ: ผมเปลี่ยนค่า J9
เป็น J0
ตรงท้าย payload jwt นะครับ เผื่อลืม format ของ jwt เป็น {Header.Payload.Signature
}
ตัวอย่าง
0.2) ลองแกล้ง โดยทำการสร้าง jwt token ด้วย symmetric key
เป็น nginx-community-thailand
แต่ในไฟล์ api_secret.jwk
ยังเหมือนเดิม.
curl -i http://localhost/?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NTk4MTI5NTcsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.n9IiB-zJ2HF9D1mb7dMRg0YoIA2uNI-JLtvkCV5lDv4
ตัวอย่าง
0.3) ลองแกล้ง โดยกำหนดค่า exp หรือ Expiration time ซึ่งต้องกำหนดค่าเป็น seconds in unix epoch ครับ โดยผมจะเปลี่ยนจาก 1659812957 =>(2022-08-07 02:09:17)
เป็น 1517417999 => (2018:01:31 23:59:59)
นั้นหมายความว่า Expire แล้ว
$ date -r '1659812957' '+%Y-%m-%d %H:%M:%S'
2022-08-07 02:09:17$ date -j -f "%Y:%m:%d %H:%M:%S" '2018:01:31 23:59:59' +%s
1517417999
ตัวอย่าง
ทำการสร้าง token ใหม่ลองดูจาก https://jwt.io
ลองเรียกเข้าไปด้วย jwt ที่หมดอายุแล้ว
หลังการทดสอบเสร็จแล้ว ก็ทำการลบ Container
docker-compose down
เรียบร้อยครับ จะเห็นว่า เราสามารถกำหนด กลุ่มของ A และ B ได้ ผ่านทาง JWT Claim ถ้าไม่ใช่ กลุ่ม A (uid=111) ก็ไปทาง B ทั้งหมด
ส่วนบทส่งท้าย คือ ผมอยากจำลอง หรือสร้างสถาณการณ์ต่างๆ ดูว่า ถ้าเกิดเหตุการณ์ต่างๆ แบบที่ผมสมมุติ ขึ้นแล้ว NGINX จะสามารถทำงานได้อย่างสมบูรณ์ หรือไม่