چند ماه پیش، من در حال پیاده سازی یک سرور 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، که ما نیز در کشور خود از آن استفاده کردیم. اینجا همه چیز راحت تر است. در حین تأیید از یک کمک مالی دیگر، علاوه بر رمز دسترسی اصلی، یک نشانه دیگر صادر می شود - Refresh Token، که فقط یک بار می تواند استفاده شود و طول عمر آن معمولاً بسیار بیشتر است. با این Refresh Token، زمانی که TTL (زمان زنده بودن) نشانه دسترسی اصلی به پایان می رسد، درخواست یک نشانه دسترسی جدید به نقطه پایانی یک کمک مالی دیگر می رسد. توکن Refresh استفاده شده بلافاصله به صفر بازنشانی می شود. این بررسی دو مرحلهای است و در پسزمینه و بهطور نامحسوس برای کاربر قابل انجام است.
3) فرمت های خروجی داده های سفارشی را تنظیم کنید
پس از اجرای کمک های مالی انتخاب شده، مجوز کار، لازم به ذکر است که اطلاعات مربوط به کاربر نهایی را دریافت کنید. OIDC یک نقطه پایانی جداگانه برای این دارد، که در آن می توانید اطلاعات کاربر را با رمز دسترسی فعلی خود و در صورت بروز بودن درخواست کنید. و اگر داده های کاربر اغلب تغییر نمی کند، و شما نیاز دارید که موارد فعلی را بارها دنبال کنید، می توانید به راه حلی مانند توکن های JWT برسید. این توکن ها نیز توسط استاندارد پشتیبانی می شوند. توکن JWT خود از سه بخش تشکیل شده است: هدر (اطلاعات مربوط به توکن)، بارگذاری (هر گونه داده لازم) و امضا (امضا، توکن توسط سرور امضا شده است و بعداً می توانید منبع امضای آن را بررسی کنید).
در پیاده سازی OIDC، توکن JWT id_token نامیده می شود. می توان آن را به همراه یک نشانه دسترسی معمولی درخواست کرد و تنها چیزی که باقی می ماند تأیید امضا است. سرور مجوز یک نقطه پایانی جداگانه برای این کار با دسته ای از کلیدهای عمومی در قالب دارد
برای مثال در گوگل:
{
"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 تایید شده باشد. این راه حل ها معمولا دارای نشان گواهی OpenID هستند.
همچنین اگر نمی خواهید سرور OIDC خود را حفظ کنید، ارائه دهندگان پولی موجود را فراموش نکنید. امروزه گزینه های خوب زیادی وجود دارد.
بعدی چیست؟
قرار است در آینده ای نزدیک ترافیک سرویس های داخلی را به روشی دیگر ببندیم. ما قصد داریم SSO فعلی خود را با استفاده از OpenResty به یک پروکسی مبتنی بر OAuth بر روی متعادل کننده منتقل کنیم. در حال حاضر بسیاری از راه حل های آماده در اینجا وجود دارد، به عنوان مثال:
مواد اضافی
منبع: www.habr.com