ایجاد صفحه احراز هویت سفارشی در لاراول – از صفر تا صد
در این مقاله، قصد داریم سیستم احراز هویت فریمورک لاراول را مورد بررسی قرار دهیم. هدف اصلی این مقاله ایجاد یک راهکار حفاظتی احراز هویت سفارشی در لاراول است که از طریق بسط سیستم احراز هویت مرکزی آن صورت میگیرد.
لاراول در هسته خود یک سیستم احراز هویت کاملاً پایدار دارد که پیادهسازی کارکرد احراز هویت را به سادگی امکانپذیر ساخته است. در واقع کافی است چند دستور آرتیزان اجرا کنید تا چارچوب یک سیستم احراز هویت آماده شود.
به علاوه خود سیستم طوری طراحی شده است که میتوان آن را بسط داد و به آداپترهای احراز هویت سفارشی نیز وصل کرد. این همان کاری است که قرار است در این مقاله انجام دهیم. پیش از آن که پا را فراتر گذارده و وارد جزییات پیادهسازی محافظ احراز هویت سفارشی شویم، کار خود را با بررسی عناصر ابتدایی سیستم احراز هویت آغاز میکنیم که محافظها و ارائه دهندهها هستند.
عناصر مرکزی: محافظها و ارائه دهندهها
سیستم احراز هویت سفارشی لاراول از دو عنصر اصلی به نام «محافظ» (Guard) و «ارائه دهنده» (Provider) تشکیل یافته است.
محافظ
محافظ را میتوان به چشم راهحل ارائه دهنده منطق برای شناسایی کاربران احراز هویت شده دید. لاراول در هسته مرکزی خود محافظهای مختلفی مانند «نشست» (Session) و «توکن» (Token) ارائه میکند. محافظ نشست، حالت کاربر را در هر درخواست به وسیله کوکی نگهداری میکند و در سوی دیگر محافظ توکن کاربر را از طریق یک توکن معتبر در هر درخواست احراز هویت میکند.
بنابراین چنان که میبینید محافظ، منطق احراز هویت را تعریف میکند و لزومی نیست که همیشه اقدام به بازیابی اطلاعات احراز هویت معتبر از بکاند بکند. شما میتوانید یک محافظ را که به سادگی حضور یک شیء خاص را در هدر درخواست بررسی میکند و کاربر را بر مبنای آن احراز هویت میکند پیادهسازی کنید.
در ادامه این مقاله ما یک محافظ پیادهسازی میکنیم که پارامترهای خاص JSON را در هدرهای درخواست بررسی میکند و کاربر معتبر را از بکاند بازیابی مینماید.
ارائه دهنده
اگر محافظ منطق احراز هویت را تعریف کند، ارائه دهنده احراز هویت مسئول بازیابی کاربر از حافظه بکاند خواهد بود. اگر محافظ الزام کند که کاربر باید در برابر حافظه بکاند اعتبارسنجی شود، در این صورت پیادهسازی بازیابی کاربر به ارائه دهنده احراز هویت سپرده میشود.
لاراول دو ارائه دهنده احراز هویت دارد که یکی Database و دیگری Eloquent است. ارائه دهنده احراز هویت Database اقدام به بازیابی مستقیم اطلاعات احراز هویت کاربر از حافظه بکاند میکند، در حالی که Eloquent لایه انتزاعی ارائه میکند که مراحل مورد نیاز را اجرا میکند.
در مثال مورد بررسی این مقاله، ما اقدام به پیادهسازی یک ارائهدهنده احراز هویت MongoDB میکنیم که اطلاعات احراز هویت کاربر را از بکاند MongoDB واکشی میکند.
بدین ترتیب مقدمه کوتاه ما در مورد محافظها و ارائه دهندهها در سیستم احراز هویت لاراول به پایان میرسد. در بخشهای بعدی روی توسعه محافظ و ارائه دهنده احراز هویت سفارشی خود متمرکز خواهیم شد.
نگاهی کوتاه به تنظیمات فایل
در ادامه به بررسی فهرست فایلهایی میپردازیم که در طی این مقاله پیادهسازی خواهیم کرد.
- config/auth.php: این فایل پیکربندی احراز هویت است که در آن یک مدخل برای محافظ سفارشی خود اضافه میکنیم.
- config/mongo.php: این فایلی است که پیکربندی MongoDB را نگهداری میکند.
- app/Services/Contracts/NosqlServiceInterface.php: این یک اینترفیس است که کلاس پایگاه داده Mongo سفارشی ما پیادهسازی میکند.
- app/Database/MongoDatabase.php: کلاس اصلی پایگاه داده است که با MongoDB تعامل دارد.
- app/Models/Auth/User.php: کلاس مدل «کاربر» (User) است که قرارداد احراز هویت را پیادهسازی میکند.
- app/Extensions/MongoUserProvider.php: یک پیادهسازی از ارائهدهنده احراز هویت است.
- app/Services/Auth/JsonGuard.php: پیادهسازی درایور محافظ احراز هویت است.
- app/Providers/AuthServiceProvider.php: یک فایل موجود است که از آن برای افزودن اتصالهای کانتینر سرویس خود استفاده میکنیم.
- app/Http/Controllers/MongoController.php: یک فایل کنترلر دمو است که برای تست محافظ سفارشی خود پیادهسازی میکنیم.
اگر فعلاً از فهرست فایلهای فوق چندان سر در نمیآورید، نباید نگران باشید، زیرا همه این موارد را در ادامه مقاله به تفصیل بررسی خواهیم کرد.
بررسی تفصیلی مراحل پیادهسازی
در این بخش به بررسی مراحل پیادهسازی فایلهای مورد نیاز خواهیم پرداخت.
نخستین کاری که باید انجام دهیم این است که در مورد محافظ سفارشی خود به لاراول اطلاع میدهیم. بدین منظور جزییات محافظ سفارشی را در فایل config/auth.php به صورت زیر وارد میکنیم:
چنان که میبینید، محافظ سفارشی خود را زیر کلید Custom اضافه کردهایم. سپس باید یک مدخل ارائهدهنده مرتبط در بخش providers اضافه کنیم:
ما مدخل ارائهدهنده خود را زیر کلید mongo اضافه کردهایم. در نهایت محافظ احراز هویت پیشفرض خود را از «وب» به «سفارشی» عوض میکنیم:
البته این ارائهدهنده هنوز کار نمیکند، زیرا هنوز فایلهای ضروری را پیادهسازی نکردهایم. این همان است که در چند بخش بعدی برسی خواهیم کرد.
راهاندازی درایور MongoDB
در این بخش فایلهایی که برای مکالمه با وهله MongoDB مورد نیاز است را پیادهسازی میکنیم.
ابتدا یک فایل پیکربندی به نام config/mongo.php ایجاد میکنیم که تنظیمات پیشفرض اتصال MongoDB را نگهداری میکند.
البته شما باید مقادیر را با تنظیمات خودتان عوض کنید. ما به جای ایجاد مستقیم یک کلاس که با MongoDB تعامل داشته باشد، در وهله نخست یک اینترفیس میسازیم. مزیت ایجاد یک اینترفیس این است که یک قرارداد ارائه میکند که هر توسعهدهندهای باید در زمان پیادهسازی از آن تبعیت کند. ضمناً پیادهسازی ما از MongoDB میتواند به سادگی درون پیادهسازی NoSQL دیگری قرار گیرد.
در ادامه یک فایل اینترفیس به نام app/Services/Contracts/NosqlServiceInterface.php با محتوای زیر ایجاد میکنیم:
این یک اینترفیس کاملاً ساده است که متدهای ابتدایی CRUD را اعلان میکند و یک کلاس نیز اعلان میکند که در آن این اینترفیس را پیادهسازی میکند.
اینک میتوانیم یک کلاس واقعی در مسیر app/Database/MongoDatabase.php تعریف میکنیم:
البته تصور میکنیم که شما قبلاً MongoDB و اکستنشن MongoDB PHP متناظر را نصب کردهاید.
متد construct__ یک کلاس را با پارامترهای ضروری وهلهسازی میکند. متد مهم دیگری که به آن علاقهمندیم متد find است که رکورد مبتنی بر معیار ارائه شده از سوی آرگومانهای متد را بازیابی میکند. این پیادهسازی درایور MongoDB بود که تلاش کردیم تا حد امکان آن را ساده حفظ کنیم.
راهاندازی مدل User
ما با پیروی از استانداردهای سیستم احراز هویت مدل User را پیادهسازی میکنیم که باید قرارداد را پیادهسازی کند. در ادامه یک فایل به نام app/Models/Auth/User.php با محتوای زیر ایجاد میکنیم:
احتمالاً تاکنون متوجه شدهاید که App\Models\Auth\User قرارداد Illuminate\Contracts\Auth\Authenticatable را پیادهسازی میکند.
اغلب متدهایی که در کلاس ما پیادهسازی شدهاند کاملاً گویا هستند. مثلاً متد fetchUserByCredentials کاربر را از بکاند موجود بازیابی میکند. در این مثال، بکاند، کلاس MongoDatabase است که برای بازیابی اطلاعات مورد نیز فراخوانی خواهد شد. بدین ترتیب کار پیادهسازی مدل User به پایان میرسد.
راهاندازی ارائه دهنده احراز هویت
چنان که پیشتر اشاره کردیم، سیستم احراز هویت لاراول شامل دو عنصر محافظ و ارائه دهنده است. در این بخش یک ارائه دهنده احراز هویت میسازیم که به منظور بازیابی کاربر از بکاند مورد استفاده قرار میگیرد. در ادامه فایلی به نام app/Extensions/MongoUserProvider.php با محتوای زیر ایجاد میکنیم:
در این مورد نیز باید مطمئن شویم که ارائهدهنده سفارشی حتماً قرارداد Illuminate\Contracts\Auth\UserProvider را پیادهسازی میکند در ادامه دو متد مهم به نامهای retrieveByCredentials و validateCredentials تعریف میکنیم.
متد retrieveByCredentials برای بازیابی احراز هویت با استفاده از کلاس مدل User استفاده میشود که در بخش قبلی ساختهایم. از سوی دیگر متد validateCredentials برای اعتبارسنجی کاربر در برابر مجموعه مفروضی از اطلاعات احراز هویت مورد استفاده قرار میگیرد.
بدین ترتیب کار پیادهسازی ارائه دهنده سفارشی ما نیز به پایان میرسد. در بخش بعدی یک محافظ ایجاد میکنیم که با ارائه دهنده احراز هویت MongoUserProvider تعامل دارد.
راهاندازی محافظ احراز هویت
چنان که قبلاً بررسی کردیم، محافظ در سیسم احراز هویت لاراول، شیوه احراز هویت کاربر را تدارک میبیند. در مثال عملی مورد بررسی در این مقاله ما اقدام به بررسی پارامتر درخواست jsondata میکنیم که باید شامل رشته اطلاعات احراز هویت باشد که به صورت JSON انکود شده است.
در این بخش یک محافظ ایجاد میکنیم که با ارائهدهنده احراز هویت که در بخش قبل ساختیم تعامل دارد. در ادامه فایلی به نام app/Services/Auth/JsonGuard.php و با محتوای زیر ایجاد میکنیم:
قبل از هر چیز کلاس ما باید اینترفیس Illuminate\Contracts\Auth\Guard را پیادهسازی کند. بدین ترتیب باید همه متدهای اعلان شده در آن اینترفیس را پیادهسازی کنیم.
نکته مهمی که باید اشاره کرد این است که تابع construct__ نیازمند یک پیادهسازی از Illuminate\Contracts\Auth\UserProvider است. در این مورد یک وهله از App\Extensions\MongoUserProvider ارسال میکنیم که در بخش بعدی آن را بررسی خواهیم کرد.
سپس یک تابع به نام getJsonParams داریم که اطلاعات احراز هویت کاربر را از پارامتر درخواست با نام jsondata بازیابی میکند. چنان که انتظار میرود ما اقدام به بازیابی یک رشته انکود شده JSON از اطلاعات احراز هویت کاربر میکنیم. به این منظور از تابع json_decode برای دیکود کردن دادههای JSON استفاده کردهایم.
در تابع اعتبارسنجی، نخستین کاری که انجام میدهیم، بررسی وجود آرگومان credentials$ است. اگر این آرگومان موجود نباشد، متد getJsonParams را برای بازیابی اطلاعات احراز هویت کاربر از پارامترهای درخواست مورد استفاده قرار میدهیم.
در ادامه متد retrieveByCredentials را از ارائهدهنده MongoUserProvider فراخوانی میکنیم که کاربر را از پایگاه داده MongoDB بکاند بازیابی میکند. در نهایت متد validateCredentials ارائهدهنده MongoUserProvider اقدام به اعتبارسنجی کاربر میکند.
بدین ترتیب کار پیادهسازی محافظ سفارشی به پایان میرسد. در بخش بعدی شیوه کنار هم قرار دادن همه این قطعات مختلف برای ساخت یک سیستم احراز هویت موفق را توضیح میدهیم.
جمعبندی اجزای مختلف
تا به اینجا همه اجزای محافظ احراز هویت سفارشی که سیستم احراز هویت جدید ما را تشکیل میدهند طراحی کرده و توسعه دادهایم. با این حال، این سیستم هنوز آماده به کار نیست، زیرا باید اول از اتصالهای کانتینر سرویس لاراول استفاده کنیم تا آن را ثبت نماییم. چنان که احتمالاً میدانید، ارائهدهنده سرویس لاراول بهترین مکان برای پیادهسازی اتصال مورد نیاز است.
در ادامه فایل app/Providers/AuthServiceProvider.php را باز میکنیم که امکان افزودن اتصالهای کانتینر سرویس احراز هویت را به ما میدهد. اگر این فایل شامل هیچ تغییر سفارشی نباشد، میتوانید آن را با محتوای زیر تعویض کنید:
در ادامه متد boot را مینویسیم که شامل اغلب اتصالهای ارائهدهنده است. در آغاز کار اتصالهایی برای عناصر App\Database\MongoDatabase و App\Models\Auth\User ایجاد میکنیم.
اینک زمان آن رسیده است که محافظ و ارائهدهنده سفارشی را به سیستم احراز هویت لاراول وصل کنیم. ما از متد Auth Facade ارائهدهنده برای افزودن ارائهدهنده احراز هویت سفارشی خود زیر کلید mongo استفاده میکنیم. به خاطر داشته باشید که این کلید تنظیمات انجام یافته قبلی در فایل auth.php را بازتاب میدهد.
به طور مشابه، پیادهسازی محافظ سفارشی خود را با استفاده از متد extend مربوط به Auth facade تزریق میکنیم.
در ادامه یک متد register وجود دارد که از آن برای اتصال اینترفیس App\Services\Contracts\NosqlServiceInterface interface به پیادهسازی App\Database\MongoDatabase استفاده میکنیم.
بدین ترتیب هر زمان که لازم باشد وابستگی App\Services\Contracts\NosqlServiceInterface برقرار شود، لاراول با پیادهسازی آداپتر App\Database\MongoDatabase پاسخ میدهد.
مزیت استفاده از این رویکرد آن است که فرد میتواند به سادگی پیادهسازی مفروض را با پیادهسازی سفارشی تعویض کند. برای نمونه تصور کنید فردی میخواهد در آینده پیادهسازی App\Database\MongoDatabase را با آداپتر CouchDB عوض کند. در این حالت، کافی است اتصال متناظر را در متد register اضافه کند.
بدین ترتیب ارائهدهنده سرویس آماده به کار شده است. در این زمان ما همه موارد لازم برای تست پیادهسازی محافظ سفارشی خود را در اختیار داریم، بنابراین در بخش بعدی به تست آن میپردازیم.
آیا سیستم ما کار میکند؟ بدین ترتیب ما همه مراحل دشوار محافظ احراز هویت سفارشی اول خود را سپری کردهایم و اینک زمان آن رسیده که از آن استفاده کرده و آن را امتحان کنیم.
در ادامه یک فایل کنترلر ابتدایی به نام app/Http/Controllers/MongoController.php مانند زیر پیادهسازی کردیم:
در ادامه نگاهی دقیق به وابستگی متد login میاندازیم که نیازمند پیادهسازی محافظ Illuminate\Contracts\Auth\Guard است. از آنجا که ما محافظ custom را به عنوان محافظ پیشفرض در فایل auth.php تنظیم کردیم، در واقع این App\Services\Auth\JsonGuard است که تزریق میشود.
سپس متد validate را از کلاس App\Services\Auth\JsonGuard فراخوانی میکنیم که به نوبه خود یک سری از فراخوانیهای متد را دارد:
- متد retrieveByCredentials را از کلاس App\Extensions\MongoUserProvider فراخوانی میکند.
- متد retrieveByCredentials اقدام به فراخوانی متد fetchUserByCredentials از کلاس User در مسیر App\Models\Auth\User میکند.
- متد fetchUserByCredentials متد find را از کلاس App\Database\MongoDatabase برای بازیابی اطلاعات احراز هویت فراخوانی میکند.
- در نهایت متد find از App\Database\MongoDatabase پاسخ را بازگشت میدهد.
اگر همه چیز مطابق انتظار اجرا شود، با فراخوانی متد user در محافظ خودمان یک کاربر احراز هویت شده به دست میآوریم.
برای دسترسی به کنترلر باید یک مسیر مرتبط در فایل routes/web.php اضافه کنید.
اگر تلاش کنید بدون هر گونه پارامتری به مسیر http://your-laravel-site/custom/mongo/login دسترسی پیدا کنید، با پیام not authorized مواجه میشوید.
از سوی دیگر، اگر آدرسی مانند آنچه در زیر آمده است را وارد کنید در پاسخ در صورتی که کاربر در پایگاه داده موجود باشد، پیام موفقیت را دریافت خواهید کرد.
http://your-laravel-site/custom/mongo/login?jsondata={"username":"admin","password":"admin"}
توجه داشته باشید که این موارد صرفاً به عنوان نمونه هستند و قصد ما نمایش طرز کار محافظ سفارشی است. شما در عمل باید از طرز عمل گردش احراز هویت و مسئولیت خود برای ایجاد یک راهحل پایدار و امن برای اپلیکیشن آگاه باشید.
سخن پایانی
فریمورک لاراول یک سیستم احراز هویت پایدار در هسته مرکزی خود دارد که در صورت نیاز میتواند برای ساخت یک سیستم احراز هویت سفارشی بسط یابد. در این مقاله به بررسی روش پیادهسازی یک محافظ سفارشی و اتصال آن به گردش کار احراز هویت لاراول پرداختیم. در طی این مسیر یک سیستم توسعه دادیم که کاربر بر مبنای یک رشته JSON در درخواست که با پایگاه داده MongoDB تطبیق مییافت، احراز هویت میشود. برای نیل به این مقصود در نهایت یک محافظ سفارشی و یک ارائهدهنده سفارشی را پیادهسازی کردیم.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی PHP
- آموزش REST API در Laravel (لاراول) با بسته Passport
- مجموعه آموزشهای برنامهنویسی
- جستجوی تمام متن در لاراول با Scout — به زبان ساده
- مدیریت پکیج در لاراول — به زبان ساده
==