- JWT ย่อมาจาก JSON Web Tokens และเป็นมาตรฐานสำหรับโทเค็นยืนยันตัวตน
- JWT ประกอบด้วย header, payload, signature หรือ message authentication code
- ผู้ที่มีคีย์สำหรับตรวจสอบสามารถยืนยันความถูกต้องแท้จริงของ payload ได้
รูปแบบการใช้งาน JWT ทั่วไป
- JWT มีข้อมูลอย่างเช่น issuer, audience, subject และเวลาหมดอายุ
- ผู้รับจะตรวจสอบความถูกต้องของโทเค็น จากนั้นตรวจว่าหมดอายุหรือยัง และถือว่า subject คือผู้ใช้ที่ผ่านการยืนยันตัวตนแล้ว
ข้อดีของ JWT
- ข้อดีหลักของ JWT คือผู้รับสามารถตรวจสอบความถูกต้องของโทเค็นได้โดยไม่ต้องเชื่อมต่อกับฐานข้อมูลผู้ใช้
- ในสภาพแวดล้อมการติดตั้งขนาดใหญ่ บริการยืนยันตัวตนอาจเป็นบริการเดียวที่เข้าถึงฐานข้อมูลผู้ใช้ส่วนกลาง
ปัญหาเรื่องการล็อกเอาต์และการทำให้เซสชันเป็นโมฆะ
- โทเค็นยืนยันตัวตนควรมีอายุสั้น เช่น สูงสุด 5 นาที
- ไคลเอนต์จะได้รับ refresh token ด้วย เพื่อใช้ขอโทเค็นยืนยันตัวตนใหม่
- refresh token ทำหน้าที่เป็นโทเค็นเซสชันตัวจริง
กรณีที่ไม่จำเป็นต้องใช้ JWT
- หากต้องการทำระบบล็อกเอาต์ ต้องเก็บ allowlist ของ JWT ที่ยังใช้ได้ หรือ denylist ของ JWT ที่ถูกเพิกถอน
- หากต้องการบล็อกผู้ใช้ ต้องตรวจสอบแฟลก "ผู้ใช้ยังใช้งานอยู่" ในฐานข้อมูล
- ต้องมีความสัมพันธ์เพิ่มเติมระหว่างออบเจ็กต์ผู้ใช้กับออบเจ็กต์อื่น
- มีการทำงานที่เกี่ยวข้องกับฐานข้อมูล
บทสรุป
- หากเข้าเงื่อนไขข้อใดข้อหนึ่งข้างต้น ก็ไม่จำเป็นต้องใช้ JWT
- การใช้ session token แบบ opaque ทั่วไปและเก็บไว้ในฐานข้อมูลจะดีกว่า
- สามารถหลีกเลี่ยงข้อเสียของ JWT และลดความซับซ้อนได้
ความเห็นของ GN⁺
- JWT เหมาะกับบริการขนาดใหญ่ แต่สำหรับบริการขนาดเล็กส่วนใหญ่ อาจเพิ่มความซับซ้อนเกินความจำเป็น
- กลไกจัดการเซสชันแบบทั่วไปเพียงพอสำหรับเว็บแอปพลิเคชันส่วนใหญ่
- การใช้ JWT อาจทำให้การทำฟีเจอร์อย่างการล็อกเอาต์และการทำให้เซสชันเป็นโมฆะทำได้ยาก
- หากต้องการใช้ประโยชน์จากข้อดีของ JWT ควรพิจารณาขนาดและข้อกำหนดของบริการอย่างรอบคอบ
- อีกทางเลือกหนึ่งคือพิจารณาเฟรมเวิร์กด้านการยืนยันตัวตนอย่าง OAuth2
8 ความคิดเห็น
เมื่อจำเป็นต้องมีการยืนยันตัวตนของไคลเอนต์ที่หลากหลาย การใช้ JWT ให้ประโยชน์หลายอย่าง
อย่างไรก็ตาม ความสามารถในการขยายระบบกับความปลอดภัยมักมุ่งไปคนละทิศทางเสมอ ดังนั้นหากความปลอดภัยมีความสำคัญเป็นพิเศษ ผมคิดว่าการใช้วิธีอื่นจะดีกว่า
โดยส่วนตัวผมมองว่าโทเค็น
jwtเหมาะจะใช้ตอนส่งข้อมูลชั่วคราวที่ไม่เป็นไรแม้จะถูกเปิดเผย ระหว่างระบบผ่านเบราว์เซอร์มากกว่าและสำหรับโทเค็นที่ใช้ยืนยันตัวตนซึ่งมีข้อมูลส่วนบุคคลอยู่ด้วย ผมคิดว่าใช้ opaque token จะดีกว่าครับ..
จากประสบการณ์ส่วนตัว ตอนทำ MVP ผมมองว่า JWT ก็มีข้อดีอยู่ครับ
ยกตัวอย่างเช่น ถ้าเป็นบริการที่ทำและดูแลคนเดียว ก็เหมือนเป็นการลดต้นทุนด้านการวางแผนจากคำขอที่เข้ามาแบบกะทันหัน เพราะความสัมพันธ์ของข้อมูลที่วางไว้ตอนแรก พอผ่านไปเดือนสองเดือนก็มักเปลี่ยนไปโดยสิ้นเชิง ในช่วงที่แผนงานยังไม่ชัดเจน ถ้าเป็นเรื่องที่เกี่ยวกับ auth ผมจำได้ว่าการจัดโครงสร้าง JWT payload ให้มีลักษณะเป็น optional field แล้วทำฟีเจอร์ไว้ก่อน ทำให้แม้ฝั่งวางแผนจะยังไม่ต้องทำงานแยกโดเมนกับแยกบริการ ก็ยังสามารถพัฒนาในรูปแบบที่แยกแค่โดเมนออกจากบริการแบบ monolithic ได้ง่าย ๆ แล้วนำไปทดสอบตลาดก่อนได้ (แล้วค่อยไปตามขั้นตอนแยกบริการภายหลัง หรือไม่ก็ยกเลิกไปเลย)
แต่ทั้งนี้ก็คงขึ้นอยู่กับโดเมนของบริการที่ต้องการสร้างด้วยครับ โปรเจ็กต์นั้นเป็นโปรเจ็กต์ที่มีการผูกกับ third party สูงมากแม้จะเป็นบริการแบบเรียลไทม์ก็ตาม... เลยจำได้ว่าตอนนั้นเลือกแนวทางนี้เพราะคิดว่าถ้ารีบพัฒนาไปมาก ๆ แล้วมี document/row ในฐานข้อมูลสะสมมหาศาล ต้นทุนในการจัดการน่าจะสูงขึ้น
แน่นอนว่าถ้าจะโฟกัสที่การทำให้เสร็จเร็ว ผมมองว่าวิธีแบบ session น่าจะดีกว่า (เพราะช่วงแรก ๆ coupling ระหว่างหลายบริการยังไม่แน่นมาก จะรื้อแล้วทำใหม่ก็สะดวก) แถมเวลาเพื่อนร่วมทีมคนอื่นเข้ามา ต้นทุนในการส่งต่องานก็ต่ำกว่าด้วย
ตอนนั้นก็คิดอยู่พักหนึ่งเหมือนกันครับ แต่พอมาย้อนดูตอนนี้ ไม่ว่าจะเลือกทำแบบไหน ผลกระทบต่อโปรเจ็กต์ก็คงไม่ได้ร้ายแรงมากนัก
โดยส่วนตัวผมคิดว่าเวลาจะใช้ API gateway การทำ auth ด้วย JWT มีข้อดีอยู่บ้าง แต่ก็อยากรู้ว่าในบริการขนาดเล็ก JWT มีข้อดีอะไรบ้าง และคุณกำลังหมายถึงกรณีที่มีการเปลี่ยนข้อมูลผู้ใช้ที่ใส่ไว้ใน JWT บ่อย ๆ ใช่ไหม?
โดยภาพรวมก็ใกล้เคียงกับที่คุณพูดไว้ครับ เพียงแต่ในกรณีนี้ไม่ได้ถึงขั้นต้องเปลี่ยนข้อมูลบ่อยเพราะโมเดลของผู้ใช้เองเปลี่ยนไป แต่จะใกล้กับกรณีที่มีการเพิ่มข้อมูลแบบ optional มากกว่า เมื่อมีการเพิ่มฟีเจอร์ใหม่หรือมีบริการใหม่ที่ต้องใช้ third-party tool ซึ่งต้องการข้อมูลเพิ่มเติมของผู้ใช้ (ถ้าจะลงรายละเอียดอีกนิด ก็คืออยู่ในสถานการณ์ที่ยังคลุมเครือว่าในอนาคตจะแยกหน่วยการจัดการ
authออกไปด้วยอะไรอย่าง API gateway หรือไม่ หรือจะมีเซิร์ฟเวอร์ตัวหนึ่งที่ทำหน้าที่ใกล้เคียงกันหรือเปล่า...)ถ้ายกตัวอย่างให้เป็นรูปธรรมขึ้นอีกหน่อย ตอนนั้นเป็นสถานการณ์ที่มีบริการ A เป็นตัวหลักอยู่ครับ เนื่องจากยังเป็นช่วง MVP จึงมีเพียงข้อมูลการชำระเงินหรือข้อมูลว่าเป็นผู้ใช้ที่ยืนยันตัวตนแล้วหรือไม่อยู่ในตารางผู้ใช้ แต่มีคำขอเข้ามาให้เพิ่มบริการ B และ C ซึ่งผู้ใช้แต่ละคนต้องมีข้อมูลการยืนยันตัวตนที่ต่างกันจึงจะใช้งานได้ ในบรรดานั้น B เองก็ยังไม่แน่ชัดว่าจะถูกรวมเข้าไปในบริการ A หรือไม่ ส่วน C ก็อาจหายไปได้ จึงอยากทดลองแบบเบา ๆ ก่อน (และฟีเจอร์จัดการแพลนนั้น ต่อให้ไม่พูดก็ควรต้องเพิ่มไว้เพื่อกันปัญหาอยู่แล้ว) นอกจากนี้ยังต้องการเริ่มต้นในรูปแบบที่ให้ B และ C ใช้งานร่วมกันได้บนหน้าเว็บบริการเดิมที่ให้บริการ A อยู่ด้วย ด้วยลักษณะของบริการที่เปิดใช้งานอยู่ ขณะที่ยังไม่ได้สร้างตารางจัดการแพลน (หรือตารางเกี่ยวกับการยืนยันตัวตนแบบทั่วไป) แล้ววาดความสัมพันธ์ของโดเมนแยกตามแต่ละบริการเพื่อทำ mapping นั้น การ query หลายตาราง (หรือหลายคอลเลกชัน) จึงเป็นสิ่งที่หลีกเลี่ยงไม่ได้ ในสถานการณ์ที่มีคนมาช่วยจัดระเบียบโปรเจกต์ ก็คงอยากประชุมกันสักสองสามครั้งเพื่อสกัดให้ชัดว่าปัญหาที่ต้องการแก้จริง ๆ คืออะไร และฟีเจอร์ที่ต้องการจริง ๆ คืออะไร แต่ตอนนั้นไม่ได้อยู่ในสภาพแวดล้อมที่รับประกันได้ว่าจะทำแบบนั้นได้ อีกทั้งก็ไม่ชัดเจนด้วยว่าจะสามารถทยอยชำระหนี้ทางเทคนิคพวกนี้ได้เมื่อไร ดังนั้นเรื่องแบบนี้จึงเป็นสิ่งที่พอคาดได้ตั้งแต่ก่อนเปิดตัวบริการ A แล้ว... พอคิดตั้งแต่ตอนวางโครงสร้างแรกว่าจะออกแบบฝั่ง
authให้ประหยัดต้นทุนการ query และต้นทุนการดูแลในอนาคตให้มากที่สุด ก็เลยเลือกใช้ JWT ครับ นอกจากนี้ก็เหมือนจะมีเรื่องยิบย่อยลักษณะคล้าย ๆ กันอีกเยอะมากด้วยแต่ตามที่พูดไว้ในท้ายคอมเมนต์ จริง ๆ แล้วไม่ว่าจะเลือกพัฒนาด้วยอะไร ก็คงไม่ได้ส่งผลใหญ่โตต่อโปรเจกต์โดยรวมมากนัก ถ้าทำด้วยเซสชัน ก็น่าจะหาวิธีรับมือในแบบของเซสชันได้เหมือนกัน กลับกัน สิ่งที่ร้ายแรงกว่ามากน่าจะเป็นการที่นักพัฒนาต้องไปทำงานของสายงานอื่น หรือการต้องเผชิญกับสถานการณ์ที่ต้นทุนการสื่อสารพังอยู่เรื่อย ๆ มากกว่า
แม้จะเหมาะกับสถาปัตยกรรมแบบโมโนลิธ แต่เมื่อถึงจุดที่ต้องแยกบางบริการออกไปหรืออยู่บนทางแยกของการขยายระบบ
jwtกับลอจิกที่อิงเซสชันก็แสดงให้เห็นถึงความแตกต่างอย่างชัดเจน ไม่ใช่แค่ในขั้นตอนการยืนยันตัวตนเท่านั้น แต่ในแง่การใช้งานของลอจิกภายใน เทคนิคในการจัดการแหล่งที่มาของข้อมูลก็น่าจะแตกต่างกันด้วย ผมจึงยังไม่แน่ใจว่าควรใช้เกณฑ์อะไรในการตัดสินว่าบริบทของบริการขนาดเล็กนั้นเหมาะสมหรือไม่ เป็นการตั้งสมมติฐานว่าทุกบริการจะต้องเล็กเสมอหรือเปล่า หรือเป็นการตั้งสมมติฐานว่าบริการขนาดใหญ่จะทำได้ไม่ง่ายก็ไม่แน่ใจ แต่ผมคิดว่าอย่างน้อยโครงสร้างของบริการที่เราสร้างก็ควรรองรับบริบทที่อาจเกิดขึ้นในสถานการณ์แบบใดก็ไม่รู้ แต่ยังคงมีประโยชน์อยู่เสมอไว้ในระดับขั้นต่ำ สมมติฐานว่าบริการขนาดเล็กจะคงเป็นเพียงบริการขนาดเล็กต่อไป ดูเหมือนจะยิ่งแคบลงเรื่อย ๆ เท่านั้นความเห็นจาก Hacker News
สรุปความคิดเห็นจาก Hacker News