احراز هویت ریل: تفکر بالاتر از کد
بیشتر چیزها در Rails به طرز قابل توجهی آسان هستند. به طرز شگفت انگیزی آسان است. اما احراز هویت و مجوز نیست. نه اینکه ریلز زیر کاپوت کار زیادی برای ساختن آنها انجام نمی دهد آسان تر. اما رفتن از راهاندازی یک API ساده در چند دقیقه، به گیجکننده در مورد نحوه اجرای ثبتنام، احراز هویت، مجوز، ورود خودکار و خروج با استفاده از تعدادی کنترلکننده، اشیاء و روشهای به هم پیوسته، میتواند کمی شوکه کننده باشد. بسیاری از آنها سفارشی
در این مرحله، من سعی خواهم کرد “بالاتر از کد” فکر کنم تا بفهمم واقعاً چه اتفاقی میافتد و امیدوارم کمی نظم به خود کد بیاورم. هدف این است که پیچیدگی نحوی را بهعنوان لایه سطحی چیزی ببینیم که انتزاعیتر است، اما در عین حال سادهتر است و در نتیجه به خاطر سپردن و استدلال آسانتر است.
شروع از صفر: تایید به عنوان یک مکالمه
اگر از ابتدا “auth” را برای وب سایت ها طراحی می کردیم، به چه چیزی نیاز داشتیم؟
برای واضح تر کردن مطالب، از یک قیاس استفاده می کنیم. اگر ما یک ربات انسان نما طراحی می کردیم که قادر به گفتگوی غنی و معنادار با مردم باشد، به چه چیزی نیاز داشتیم؟
ایده در اینجا این است که احراز هویت در وب سایت باید مانند مکالمه با شخصی باشد که شما را می شناسد و به ویژگی های فردی شما پاسخ می دهد.
داده های کاربر
بدیهی است که ما باید در مورد کاربران بدانیم. ما باید دادههای مربوط به آنها را ذخیره کنیم، از جمله اما نه لزوماً به ویژگیهای شناسایی آنها، که نام کاربری و رمز عبور واضحترین آنهاست.
اگر به استعاره خود برگردیم، اگر ربات ما قادر به انجام مکالمات غنی و معنادار با مردم باشد، به ذخیرهای از دادههای کاربر مانند نام، ظاهر چهره، سن، دوستداشتن و دوست نداشتن، آخرین مکالمه و غیره نیاز دارد.
در اصطلاح Rails، ما به a User
منبع ما می خواهیم بتوانیم در صورت نیاز کاربران را اضافه و بازیابی کنیم، بنابراین از کاربران می خواهیم# ایجاد و users#show
مسیرها، حداقل
وضعیت پشتیبان
آیا صرف دانستن در مورد کاربران کافی است؟ یه جورایی سوال جالبیه به قیاس ربات ما برگردید. آیا دسترسی ربات ما به اطلاعات کاربر کافی است؟
خیر
هدف فقط داشتن ذخیرهای از دادههای کاربر نیست، بلکه داشتن رباتی است که بتواند به طور معناداری بر اساس کاربر به کاربر گفتگو کند. تمام داده های کاربر در جهان هیچ فایده ای نخواهد داشت مگر اینکه ربات نیز بداند سازمان بهداشت جهانی در هر لحظه با او صحبت می کرد.
در مقابل.
بنابراین ربات ما نیاز به نمایشی از “اینجا و اکنون” دارد. جدول کاربر به خودی خود هیچ کاربری را به عنوان شخصی که با او صحبت می شود انتخاب نمی کند. این فقط یک سری از صدها یا هزاران ردیف است که هر کدام شبیه آخرین ردیف است. جدول به خودی خود کاملاً خنثی است در حالی که نمایش اینجا و اکنون ما باید بسیار خاص باشد.
بنابراین ما نیاز به نمایشی از حالت اینجا و اکنون داریم که کاربر خاصی را به عنوان شریک مکالمه انتخاب می کند. در حال حاضر، من به سادگی به این نمایندگی به عنوان ایالت اشاره می کنم.
از نظر ریل، آیا حالت صرفاً منبع دیگری است؟ خب، ممکن است بخواهیم حالت را ایجاد، بهروزرسانی و نابود کنیم، که به معنای ایجاد مسیرها و کنترلکننده حالت است. اما ایالت نمی تواند فقط یک منبع دیگر باشد. نقش ویژه ای دارد. ایجاد یک جدول دیگر با ردیف هایی که برای نمونه های حالت نگاشت شده اند کافی نیست، همانطور که داشتن یک دسته از آشنایان ذخیره شده در حافظه به شما نمی گوید که با چه کسی صحبت می کنید. همین الان.
دولت باید مال خودش باشد! در Rails، حالت به عنوان یک شی به نام “session” با a نشان داده می شود :user_id
صفت.
مراحل بعدی
ما در واقع پیشرفت کرده ایم. ما یک بنیاد ایجاد کرده ایم. ما می دانیم که تمام فعالیت های خود را بر اساس دو نهاد قرار خواهیم داد:
- ذخیره ای از داده های کاربر در قالب یک جدول کاربر که نشان دهنده افرادی است که ما با آنها می شناسیم
- یک نمایش وضعیت back-end به شکل شی جلسه با
:user_id
ویژگی که نشان دهنده افرادی است که در اینجا و اکنون با آنها صحبت می کنیم. طبق قرارداد، اگر چنین شخصی وجود نداشته باشد:user_id
خواهد بودnil
.
اکنون، زمانی که میخواهیم عملکرد خاصی را پیادهسازی کنیم، میتوانیم بر حسب این دو موجودیت فکر کنیم. اولین سوال این است که ما میخواهیم با این دو موجودیت چه کنیم، سپس به کدام روش Rails نیاز داریم تا این کار را انجام دهیم.
بیایید برخی از توابع تأیید اعتبار استاندارد را یکی یکی مرور کنیم و ببینیم که چگونه به موجودیت های ما نقشه می دهیم.
ثبت نام
در اینجا ما یک کاربر جدید ایجاد می کنیم و سپس به آن کاربر اجازه می دهیم تا در واقع شروع به استفاده از وب سایت کند.
در رابطه با ربات ما، ما در حال معرفی یک آشنای جدید هستیم و از ربات می خواهیم با آن آشنا گفتگو کند.
بنابراین ما می خواهیم 1) یک کاربر به جدول کاربر اضافه کنیم و 2) جلسه را به روز کنیم[:user_id] ویژگی برای شروع “مکالمه”.
وارد شدن
در اینجا ما بررسی می کنیم که آیا اعتبار یک کاربر با چیزی در ذخیره اطلاعات کاربر ما مطابقت دارد یا خیر. در صورت موفقیت آمیز بودن بررسی، کاربر شروع به استفاده از وب سایت می کند.
از نظر ربات ما، ربات شریک مکالمه قبلی را می شناسد، سپس مکالمه را با آن فرد آغاز می کند.
بنابراین ما می خواهیم 1) محتویات جدول کاربر را در برابر اعتبارنامه های ارسالی بررسی کنیم و 2) به روز رسانی کنیم session[:user_id]
ویژگی برای شروع “مکالمه”.
در Rails، احراز هویت فی نفسه در واقع تنها بخشی از مفهوم ما از بررسی جدول کاربر در برابر اعتبارنامه ها است. با یک تماس ساده می توان این کار را انجام داد authenticate
روش.
user = User.find_by(username: params[:username])
user&.authenticate(params[:password])
مجوز
مجوز تا جایی که شامل بررسی ویژگی های کاربری است که دارای قبلا، پیش از این وارد شده.
از نظر ربات ما، میتوانیم این را به عنوان رباتی در نظر بگیریم که اطلاعات مربوط به شریک مکالمه فعلی خود را بازیابی میکند و آن اطلاعات را برای راهنمایی در مورد چگونگی پاسخ بررسی میکند.
اینجا جلسه[:user_id] قبلاً تنظیم شده است زیرا می توان فرض کرد که مکالمه آغاز شده است. مشکل این است که :user_id
فقط اشاره ای به یک رکورد در جدول است. شی جلسه شامل خود نمونه کاربر نیست. ما هنوز باید داده های موجود در رکورد را بازیابی کنیم تا بتوانیم تصمیم بگیریم که چگونه روی آن عمل کنیم.
بنابراین، باید یک متغیر نمونه تنظیم کنیم @user
بر اساس :user id
.
@user = User.find_by(id: session[:user_id])
این یک محدودیت را نشان می دهد که چگونه Rails مفهوم ما را از وضعیت back-end “اینجا و اکنون” نشان می دهد. این شامل نمونه کامل کاربر نیست. بنابراین، قبل از هر اقدامی که اطلاعات خاص کاربر را بازیابی می کند، باید صریحاً آن اطلاعات را به عنوان مرحله ای از فرآیند مجوز بازیابی کنیم.
خروج
خروج از سیستم مشابه پایان دادن به یک مکالمه است. پایان دادن به مکالمه به معنای فراموش کردن آن فرد نیست، بنابراین می دانیم که جدول کاربران را به حال خود رها می کنیم. تنها کاری که واقعاً باید انجام دهیم این است که به روز رسانی کنیم session[:user_id]
ویژگی برای منعکس کردن تغییر به حالت تهی.
از یک صفر :user_id
معادل حالت “بدون مکالمه” است، ما می توانیم این کار را به سادگی با حذف ویژگی انجام دهیم:
session.delete :user_id
ورود خودکار
ورود خودکار مورد جالبی است. برای مقاصد فعلی، ورود خودکار شبیه به موقعیتی است که در آن مکالمه با ربات ما از قبل برقرار است. جدول کاربر و session[:user_id]
همان طور که باید باشند هستند. ما فقط باید بررسی کنیم که آیا غیر صفر وجود دارد یا خیر:user_id
ویژگی و در صورت وجود، آن اطلاعات را برای آن کاربر به قسمت جلویی ارسال کنید.
خلاصه
از آنجایی که هدف این پست کاهش پیچیدگی است، میتوانیم کارکرد احراز هویت خود را بر اساس نوع کارهایی که برای کدام یک از دو نهاد کلیدی خود انجام میدهیم، سازماندهی کنیم. به صورت خلاصه:
- ثبت نام: به روز رسانی جدول، به روز رسانی وضعیت پشتیبان
- ورود به سیستم: بررسی جدول، بهروزرسانی وضعیت پشتیبان
- مجوز: بررسی وضعیت back-end
- خروج: به روز رسانی وضعیت پشتیبان
- ورود خودکار: بررسی وضعیت پشتیبان
باز هم، در اینجا منظور ما از جدول، ذخیره داده های کاربر است و منظور از حالت، نمایش ما از “مکالمه” در حال انجام است.
یکی از اخطارهای مهم این است که نمایش وضعیت ما نمی تواند اطلاعات کامل کاربر را نگه دارد، بنابراین بررسی وضعیت معمولاً به معنای تنظیم یک متغیر نمونه است. @user
که حاوی داده های مربوطه است.
نقشه برداری به MVC
مشکل بعدی در مورد auth در Rails، نگاشت این مفاهیم به مسیرها و کنترلرها است.
متأسفانه، اینجا جایی است که برخی از خط ها کمی تار می شوند. حفظ تفکیک سنتی نگرانی ها سخت تر می شود.
ما دیدیم که auth بر اساس جدول کاربران و شی جلسه است. به عنوان اولین گذر، وسوسه انگیز است که فرض کنیم برای هر دوی اینها به منابع Rails نیاز داریم، به طوری که هر کدام جدول، مدل، کنترلر و مسیرهای RESTFUL خود را دارند.
با این حال، به دلایلی باید از تنظیمات معمولی Rails خارج شویم.
1) شی جلسه فقط یکی دیگر از منابع Rails نیست. همانطور که دیدیم نقش مهمی را به عنوان نمایش وضعیت back-end ایفا می کند.
2) اقدامات کنترل کننده کاربر مانند create
(برای ثبت نام کاربر) و show
(برای ورود خودکار کاربر) باید شی جلسه را به روز کند.
3) اقدامات کنترل جلسه مانند create
(برای ورود کاربر) و destroy
(برای خروج) در واقع جلسه را ایجاد یا نابود نکنید. در عوض، آنها را به روز می کنند session[:user_id]
صفت.
4) یک عمل مهم تنظیم a وجود دارد @user
متغیر نمونه بر اساس وضعیت back-end ما. در حالی که این امر به طور اساسی شامل session[:user_id]
ویژگی، این یک عمل در کنترلر جلسه نیست. در عوض، قبل از هر اقدامی (بدون توجه به کنترل کننده) که نیاز به مجوز دارد، باید دوباره تنظیم شود. این معمولا با ریل انجام می شود before_action
فیلتر کنید.
نتیجه
پیاده سازی auth را می توان با اندیشیدن به آن در قالب مفاهیم انتزاعی تر اما ابتدایی تر درک کرد. برای اطمینان، تناسب کاملا تمیز نیست، به خصوص در برخی از جزئیات ریز. اما دیدن این عدم تطابق ها خود می تواند ابزار مفیدی برای یادآوری نکات و نکات این موضوع پیچیده باشد.