ไม่กี่เดือนที่ผ่านมา ฉันใช้เซิร์ฟเวอร์ OpenID Connect เพื่อจัดการการเข้าถึงแอปพลิเคชันภายในหลายร้อยรายการของเรา จากการพัฒนาของเราเอง อำนวยความสะดวกในขนาดที่เล็กลง เราได้ก้าวไปสู่มาตรฐานที่ยอมรับโดยทั่วไป การเข้าถึงผ่านบริการส่วนกลางช่วยลดความยุ่งยากในการทำงานที่ซ้ำซากจำเจ ลดค่าใช้จ่ายในการดำเนินการอนุญาต ช่วยให้คุณค้นหาโซลูชันสำเร็จรูปมากมายและไม่ต้องเปลืองสมองเมื่อพัฒนาโซลูชันใหม่ ในบทความนี้ ฉันจะพูดถึงการเปลี่ยนแปลงนี้และการกระแทกที่เราจัดการเพื่อเติมเต็ม
นานมาแล้ว... มันเริ่มต้นอย่างไร
ไม่กี่ปีที่ผ่านมา เมื่อมีแอปพลิเคชันภายในจำนวนมากเกินไปสำหรับการควบคุมด้วยตนเอง เราเขียนแอปพลิเคชันเพื่อควบคุมการเข้าถึงภายในบริษัท เป็นแอปพลิเคชัน Rails แบบธรรมดาที่เชื่อมต่อกับฐานข้อมูลที่มีข้อมูลเกี่ยวกับพนักงาน ซึ่งมีการกำหนดค่าการเข้าถึงฟังก์ชันต่างๆ ในเวลาเดียวกัน เราเพิ่ม SSO แรกซึ่งขึ้นอยู่กับการตรวจสอบโทเค็นจากฝั่งไคลเอนต์และเซิร์ฟเวอร์การอนุญาต โทเค็นถูกส่งในรูปแบบเข้ารหัสด้วยพารามิเตอร์หลายตัวและตรวจสอบบนเซิร์ฟเวอร์การอนุญาต นี่ไม่ใช่ตัวเลือกที่สะดวกที่สุด เนื่องจากแอปพลิเคชันภายในแต่ละรายการต้องอธิบายเลเยอร์ของตรรกะจำนวนมาก และฐานข้อมูลพนักงานได้รับการซิงโครไนซ์อย่างสมบูรณ์กับเซิร์ฟเวอร์การอนุญาต
หลังจากนั้นไม่นาน เราตัดสินใจลดความซับซ้อนของงานการอนุญาตจากส่วนกลาง SSO ถูกโอนไปยังบาลานเซอร์ ด้วยความช่วยเหลือของ OpenResty เทมเพลตถูกเพิ่มเข้าไปใน Lua ซึ่งตรวจสอบโทเค็น รู้ว่าคำขอนั้นกำลังจะไปที่แอปพลิเคชันใด และสามารถตรวจสอบได้ว่ามีการเข้าถึงที่นั่นหรือไม่ วิธีการนี้ทำให้งานควบคุมการเข้าถึงแอปพลิเคชันภายในง่ายขึ้นอย่างมาก - ในโค้ดของแต่ละแอปพลิเคชัน ไม่จำเป็นต้องอธิบายตรรกะเพิ่มเติมอีกต่อไป เป็นผลให้เราปิดการรับส่งข้อมูลจากภายนอกและแอปพลิเคชันเองก็ไม่ทราบอะไรเลยเกี่ยวกับการให้สิทธิ์
อย่างไรก็ตาม ยังมีปัญหาหนึ่งที่ยังไม่ได้รับการแก้ไข แล้วแอพพลิเคชั่นที่ต้องการข้อมูลเกี่ยวกับพนักงานล่ะ? เป็นไปได้ที่จะเขียน API สำหรับบริการการให้สิทธิ์ แต่คุณจะต้องเพิ่มตรรกะเพิ่มเติมสำหรับแต่ละแอปพลิเคชันดังกล่าว นอกจากนี้ เราต้องการเลิกพึ่งพาหนึ่งในแอปพลิเคชันที่เขียนขึ้นเองของเรา ซึ่งมุ่งเน้นในอนาคตสำหรับการแปลเป็น OpenSource บนเซิร์ฟเวอร์การอนุญาตภายในของเรา เราจะพูดถึงเรื่องนี้อีกครั้ง วิธีแก้ไขปัญหาทั้งสองคือ OAuth
ตามมาตรฐานทั่วไป
OAuth เป็นมาตรฐานการให้สิทธิ์ที่เข้าใจได้และเป็นที่ยอมรับโดยทั่วไป แต่เนื่องจากฟังก์ชันการทำงานไม่เพียงพอ พวกเขาจึงเริ่มพิจารณา OpenID Connect (OIDC) ในทันที OIDC เองเป็นการดำเนินการครั้งที่สามของมาตรฐานการรับรองความถูกต้องแบบเปิด ซึ่งไหลเข้าสู่ส่วนเสริมบนโปรโตคอล OAuth 2.0 (โปรโตคอลการอนุญาตแบบเปิด) โซลูชันนี้ปิดปัญหาการขาดข้อมูลเกี่ยวกับผู้ใช้และยังทำให้สามารถเปลี่ยนผู้ให้บริการอนุญาตได้
อย่างไรก็ตาม เราไม่ได้เลือกผู้ให้บริการรายใดรายหนึ่งและตัดสินใจเพิ่มการผสานรวมกับ OIDC สำหรับเซิร์ฟเวอร์การให้สิทธิ์ที่มีอยู่ของเรา การสนับสนุนการตัดสินใจครั้งนี้คือข้อเท็จจริงที่ว่า OIDC มีความยืดหยุ่นมากในแง่ของการให้สิทธิ์ผู้ใช้ปลายทาง ดังนั้นจึงเป็นไปได้ที่จะใช้การสนับสนุน OIDC บนเซิร์ฟเวอร์การอนุญาตปัจจุบันของคุณ
วิธีของเราในการปรับใช้เซิร์ฟเวอร์ OIDC ของเราเอง
1) นำข้อมูลมาสู่แบบฟอร์มที่ต้องการ
ในการรวม OIDC จำเป็นต้องนำข้อมูลผู้ใช้ปัจจุบันมาไว้ในแบบฟอร์มที่มาตรฐานเข้าใจได้ ใน OIDC สิ่งนี้เรียกว่าการเรียกร้อง การอ้างสิทธิ์เป็นฟิลด์สุดท้ายในฐานข้อมูลผู้ใช้ (ชื่อ อีเมล โทรศัพท์ ฯลฯ) มีอยู่
กลุ่มของตราสัญลักษณ์จะรวมกันเป็นส่วนย่อยต่อไปนี้ - ขอบเขต ในระหว่างการให้สิทธิ์ การเข้าถึงจะไม่ถูกร้องขอเฉพาะแบรนด์ แต่ให้เข้าถึงขอบเขต แม้ว่าบางแบรนด์จากขอบเขตจะไม่จำเป็นก็ตาม
2) ดำเนินการตามทุนที่จำเป็น
ส่วนถัดไปของการรวม OIDC คือการเลือกและการใช้งานประเภทการให้สิทธิ์ ซึ่งเรียกว่าการให้สิทธิ์ สถานการณ์เพิ่มเติมของการโต้ตอบระหว่างแอปพลิเคชันที่เลือกและเซิร์ฟเวอร์การให้สิทธิ์จะขึ้นอยู่กับการให้สิทธิ์ที่เลือก รูปแบบตัวอย่างสำหรับการเลือกทุนที่เหมาะสมแสดงไว้ในภาพด้านล่าง
สำหรับการสมัครครั้งแรก เราใช้รหัสการให้สิทธิ์ที่พบมากที่สุด ความแตกต่างจากที่อื่นคือมีสามขั้นตอนคือ อยู่ระหว่างการทดสอบเพิ่มเติม ขั้นแรก ผู้ใช้ทำการขออนุญาตรับโทเค็น - รหัสการอนุญาต จากนั้นใช้โทเค็นนี้ราวกับว่าใช้ตั๋วสำหรับการเดินทาง ขอโทเค็นการเข้าถึง การโต้ตอบหลักทั้งหมดของสคริปต์การให้สิทธิ์นี้ขึ้นอยู่กับการเปลี่ยนเส้นทางระหว่างแอปพลิเคชันและเซิร์ฟเวอร์การให้สิทธิ์ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับทุนนี้ได้
OAuth ยึดตามแนวคิดที่ว่าโทเค็นการเข้าถึงที่ได้รับหลังจากการให้สิทธิ์ควรเป็นแบบชั่วคราวและควรเปลี่ยนแปลงโดยเฉลี่ยทุกๆ 10 นาที การให้รหัสอนุญาตเป็นการตรวจสอบสามขั้นตอนผ่านการเปลี่ยนเส้นทาง ทุก ๆ 10 นาทีเพื่อเปลี่ยนขั้นตอนดังกล่าว ตรงไปตรงมา ไม่ใช่งานที่น่าพอใจที่สุดสำหรับสายตา เพื่อแก้ปัญหานี้มีการอนุญาตอื่น - Refresh Token ซึ่งเราใช้ในประเทศของเราด้วย ทุกอย่างง่ายขึ้นที่นี่ ในระหว่างการตรวจสอบจากการอนุญาตอื่น นอกจากโทเค็นการเข้าถึงหลักแล้ว ยังมีการออกโทเค็นใหม่อีกอันหนึ่ง นั่นคือ รีเฟรชโทเค็น ซึ่งสามารถใช้ได้เพียงครั้งเดียวและอายุการใช้งานมักจะยาวนานกว่านั้นมาก ด้วยโทเค็นการรีเฟรชนี้ เมื่อ TTL (Time to Live) ของโทเค็นการเข้าถึงหลักสิ้นสุดลง คำขอสำหรับโทเค็นการเข้าถึงใหม่จะมาถึงจุดสิ้นสุดของการอนุญาตอื่น โทเค็นการรีเฟรชที่ใช้จะถูกรีเซ็ตเป็นศูนย์ทันที การตรวจสอบนี้มีสองขั้นตอนและสามารถดำเนินการในพื้นหลังโดยที่ผู้ใช้มองไม่เห็น
3) ตั้งค่ารูปแบบเอาต์พุตข้อมูลแบบกำหนดเอง
หลังจากใช้การให้สิทธิ์ที่เลือกแล้ว การอนุญาตจะทำงาน เป็นเรื่องที่ควรค่าแก่การกล่าวถึงการรับข้อมูลเกี่ยวกับผู้ใช้ปลายทาง OIDC มีจุดสิ้นสุดแยกต่างหากสำหรับสิ่งนี้ ซึ่งคุณสามารถขอข้อมูลผู้ใช้ด้วยโทเค็นการเข้าถึงปัจจุบันของคุณและดูว่าเป็นปัจจุบันหรือไม่ และถ้าข้อมูลของผู้ใช้ไม่เปลี่ยนแปลงบ่อยนัก และคุณต้องติดตามข้อมูลปัจจุบันหลายๆ ครั้ง คุณก็สามารถใช้วิธีแก้ปัญหาเช่นโทเค็น JWT ได้ โทเค็นเหล่านี้ได้รับการสนับสนุนโดยมาตรฐาน โทเค็น JWT นั้นประกอบด้วยสามส่วน: ส่วนหัว (ข้อมูลเกี่ยวกับโทเค็น), เพย์โหลด (ข้อมูลที่จำเป็นใดๆ) และลายเซ็น (ลายเซ็น โทเค็นได้รับการลงนามโดยเซิร์ฟเวอร์ และคุณสามารถตรวจสอบแหล่งที่มาของลายเซ็นได้ในภายหลัง)
ในการใช้งาน OIDC โทเค็น JWT เรียกว่า id_token สามารถขอได้พร้อมกับโทเค็นการเข้าถึงปกติ ที่เหลือคือการตรวจสอบลายเซ็น เซิร์ฟเวอร์การอนุญาตมีจุดสิ้นสุดแยกต่างหากสำหรับสิ่งนี้ด้วยคีย์สาธารณะจำนวนมากในรูปแบบ
ตัวอย่างเช่นใน Google:
{
"issuer": "https://accounts.google.com",
"authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
"device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
"token_endpoint": "https://oauth2.googleapis.com/token",
"userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
"revocation_endpoint": "https://oauth2.googleapis.com/revoke",
"jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
"response_types_supported": [
"code",
"token",
"id_token",
"code token",
"code id_token",
"token id_token",
"code token id_token",
"none"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"scopes_supported": [
"openid",
"email",
"profile"
],
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"client_secret_basic"
],
"claims_supported": [
"aud",
"email",
"email_verified",
"exp",
"family_name",
"given_name",
"iat",
"iss",
"locale",
"name",
"picture",
"sub"
],
"code_challenge_methods_supported": [
"plain",
"S256"
],
"grant_types_supported": [
"authorization_code",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:ietf:params:oauth:grant-type:jwt-bearer"
]
}
ดังนั้น เมื่อใช้ id_token คุณสามารถถ่ายโอนเครื่องหมายรับรองคุณภาพที่จำเป็นทั้งหมดไปยังเพย์โหลดของโทเค็น และไม่ต้องติดต่อเซิร์ฟเวอร์การให้สิทธิ์เพื่อขอข้อมูลผู้ใช้ในแต่ละครั้ง ข้อเสียของแนวทางนี้คือการเปลี่ยนแปลงข้อมูลผู้ใช้จากเซิร์ฟเวอร์ไม่ได้เกิดขึ้นทันที แต่มาพร้อมกับโทเค็นการเข้าถึงใหม่
ผลการดำเนินการ
ดังนั้น หลังจากติดตั้งเซิร์ฟเวอร์ OIDC ของเราเองและกำหนดค่าการเชื่อมต่อกับเซิร์ฟเวอร์ในฝั่งแอปพลิเคชัน เราจึงแก้ปัญหาการถ่ายโอนข้อมูลเกี่ยวกับผู้ใช้ได้
เนื่องจาก OIDC เป็นมาตรฐานแบบเปิด เราจึงมีตัวเลือกในการเลือกผู้ให้บริการที่มีอยู่หรือการติดตั้งเซิร์ฟเวอร์ เราลองใช้ Keycloak ซึ่งสะดวกมากในการกำหนดค่า หลังจากตั้งค่าและเปลี่ยนการกำหนดค่าการเชื่อมต่อในฝั่งแอปพลิเคชันแล้ว ก็พร้อมใช้งาน ในด้านแอปพลิเคชัน สิ่งที่เหลืออยู่คือการเปลี่ยนการกำหนดค่าการเชื่อมต่อ
พูดคุยเกี่ยวกับโซลูชันที่มีอยู่
ภายในองค์กรของเรา ในฐานะเซิร์ฟเวอร์ OIDC เครื่องแรก เราได้รวบรวมการใช้งานของเราเอง ซึ่งได้รับการเสริมเพิ่มเติมตามความจำเป็น หลังจากตรวจสอบโซลูชันสำเร็จรูปอื่นโดยละเอียดแล้ว เราสามารถพูดได้ว่านี่เป็นจุดที่สงสัย เพื่อสนับสนุนการตัดสินใจติดตั้งเซิร์ฟเวอร์ของตนเอง มีความกังวลในส่วนของผู้ให้บริการในกรณีที่ไม่มีฟังก์ชันการทำงานที่จำเป็น เช่นเดียวกับการมีอยู่ของระบบเก่าซึ่งมีการอนุญาตแบบกำหนดเองที่แตกต่างกันสำหรับบริการบางอย่างและค่อนข้างมาก มีการจัดเก็บข้อมูลเกี่ยวกับพนักงานไว้แล้ว อย่างไรก็ตาม ในการใช้งานแบบสำเร็จรูปนั้นมีสิ่งอำนวยความสะดวกสำหรับการรวมเข้าด้วยกัน ตัวอย่างเช่น Keycloak มีระบบจัดการผู้ใช้ของตัวเองและมีการจัดเก็บข้อมูลโดยตรงในนั้น และจะไม่ยากที่จะแซงหน้าผู้ใช้ของคุณที่นั่น ในการทำเช่นนี้ Keycloak มี API ที่จะช่วยให้คุณดำเนินการถ่ายโอนที่จำเป็นทั้งหมดได้อย่างเต็มที่
อีกตัวอย่างหนึ่งของการนำไปใช้ที่ได้รับการรับรองและน่าสนใจในความคิดของฉันคือ Ory Hydra น่าสนใจเพราะประกอบด้วยส่วนประกอบต่างๆ ในการผสานรวม คุณจะต้องเชื่อมโยงบริการการจัดการผู้ใช้ของคุณกับบริการการให้สิทธิ์และขยายตามความจำเป็น
Keycloak และ Ory Hydra ไม่ใช่โซลูชันที่หาซื้อได้ตามร้านค้าทั่วไป เป็นการดีที่สุดที่จะเลือกการใช้งานที่รับรองโดย OpenID Foundation โซลูชันเหล่านี้มักจะมีตรารับรอง OpenID
นอกจากนี้ อย่าลืมเกี่ยวกับผู้ให้บริการแบบชำระเงินที่มีอยู่ หากคุณไม่ต้องการเก็บเซิร์ฟเวอร์ OIDC ของคุณไว้ วันนี้มีตัวเลือกดีๆมากมาย
มีอะไรต่อไป
ในอนาคตอันใกล้นี้ เราจะปิดการรับส่งข้อมูลไปยังบริการภายในด้วยวิธีอื่น เราวางแผนที่จะโอน SSO ปัจจุบันของเราบนบาลานเซอร์โดยใช้ OpenResty ไปยังพร็อกซีตาม OAuth มีโซลูชันสำเร็จรูปมากมายที่นี่ เช่น:
วัสดุเพิ่มเติม
ที่มา: will.com