Anophel-آنوفل احراز هویت بدون رمز عبور در لاراول

احراز هویت بدون رمز عبور در لاراول

تاریخ انتشار:
Laravel
زمان مطالعه: 6 دقیقه

بعضی وقت ها ما نمی خواهیم کاربران رمز عبور داشته باشند. بعضی وقت ها هم می خواهیم یک لینک جادویی به آدرس ایمیل یک کاربر ارسال کنیم و از او بخواهیم برای دسترسی به آن کلیک کند.

 

در این آموزش، من روندی را طی می‌کنم که می‌توانید برای پیاده‌سازی آن از برای پروژه های تان استفاده کنید. تمرکز اصلی ما ایجاد یک URL امضا شده است که به ما این امکان را می دهد که یک URL خاص را به آدرس ایمیل کاربران ارسال کنیم و فقط آن شخص باید بتواند به این URL دسترسی داشته باشد.

 

ابتدا  فیلد رمز عبور را در migration ، مدل(Model) حذف می کنیم. از آنجایی که این مورد نیاز نخواهد بود، می‌خواهیم اطمینان حاصل کنیم که آن را حذف کرده‌ایم، زیرا به‌طور پیش‌فرض یک ستون nullable نمی باشد. در همین حین ، می‌توانیم جدول بازنشانی رمز عبور را حذف کنیم، زیرا رمز عبوری برای بازنشانی نخواهیم داشت.

 

سپس می رویم به قسمت Route ها، ما در اینجا از Livewire استفاده می کنیم. بیایید نگاهی به این route بیندازیم:

 

Route::middleware(['guest'])->group(static function (): void {
    Route::view('login', 'app.auth.login')->name('login');
});

 

ما یک میدلور(Middleware) برای route تعیین می کنیم تا اگر کاربر قبلاً وارد سیستم شده است، route را تغییر دهیم. اجازه دهید از طریق مؤلفه Livewire که برای فرم ورود استفاده خواهیم کرد، قدم برداریم.

 

final class LoginForm extends Component
{
    public string $email = '';
 
    public string $status = '';
 
    public function submit(SendLoginLink $action): void
    {
        $this->validate();
 
        $action->handle(
            email: $this->email,
        );
 
        $this->status = 'An email has been sent for you to log in.';
    }
 
    public function rules(): array
    {
        return [
            'email' => [
                'required',
                'email',
                Rule::exists(
                    table: 'users',
                    column: 'email',
                ),
            ]
        ];
    }
 
    public function render(): View
    {
        return view('livewire.auth.login-form');
    }
}

 

مؤلفه ما دارای دو ویژگی است که می خواهیم از آنها استفاده کنیم. ایمیل برای گرفتن ورودی فرم استفاده می شود. سپس وضعیت status است، ما متدی داریم که قوانین اعتبارسنجی را برمی گرداند. این رویکرد ترجیحی من برای قوانین اعتبارسنجی درLivewire است. روش ارسال ما روش اصلی برای این کامپوننت است، و این یک قرارداد نامگذاری است که من هنگام برخورد با اجزای فرم از آن استفاده می کنم. این برای من بسیار منطقی است، اما با خیال راحت روش نامگذاری را انتخاب کنید که برای شما مناسب باشد. ما از کانتینر Laravels برای تزریق یک کلاس به action$ این متد استفاده می کنیم تا منطق ایجاد و ارسال URL امضا شده را به اشتراک بگذاریم. تنها کاری که در اینجا باید انجام دهیم این است که ایمیل وارد شده را به action$ منتقل کنیم و status را تنظیم می کنیم که به کاربر بگویم ایمیل در حال ارسال است.

 

حالا بیایید از طریق action$ که می خواهیم استفاده کنیم قدم برداریم.

 

 

final class SendLoginLink
{
    public function handle(string $email): void
    {
        Mail::to(
            users: $email,
        )->send(
            mailable: new LoginLink(
                url: URL::temporarySignedRoute(
                    name: 'login:store',
                    parameters: [
                        'email' => $email,
                    ],
                    expiration: 3600,
                ),
            )
        );
    }
}

 

 

این action$ فقط نیاز به ارسال ایمیل دارد. اگر بخواهیم می‌توانیم این را به‌گونه‌ای پیکربندی کنیم که در صف قرار گیرد - اما وقتی با یک اقدام نیاز به پردازش سریع داریم، بهتر است اگر در حال ساختن یک API هستیم، آن را در صف قرار دهیم. ما یک کلاس mailable به نام LoginLink داریم که URL مورد نظر را پاس می کند. URL ما با ارسال نام route ی که می‌خواهیم، یک route برای آن ایجاد می کنیم و پاس دادن پارامترهایی که می‌خواهیم را به عنوان بخشی از امضا استفاده می کنیم ایجاد می‌شوند.

 

final class LoginLink extends Mailable
{
    use Queueable, SerializesModels;
 
    public function __construct(
        public readonly string $url,
    ) {}
 
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Your Magic Link is here!',
        );
    }
 
    public function content(): Content
    {
        return new Content(
            markdown: 'emails.auth.login-link',
            with: [
                'url' => $this->url,
            ],
        );
    }
 
    public function attachments(): array
    {
        return [];
    }
}

 

کلاس mailable ما نسبتاً ساده است . ما یک رشته برای URL ارسال می کنیم. سپس، می‌خواهیم این را به view منتقل کنیم.

 

<x-mail::message>
# Login Link
 
Use the link below to log into the {{ config('app.name') }} application.
 
<x-mail::button :url="$url">
Login
</x-mail::button>
 
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>

 

کاربر این ایمیل را دریافت می کند و روی لینک کلیک می کند و آن را به URL امضا شده می برد. بیایید این route را ثبت کنیم و ببینیم چگونه به نظر می رسد.

 

Route::middleware(['guest'])->group(static function (): void {
    Route::view('login', 'app.auth.login')->name('login');
    Route::get(
        'login/{email}',
        LoginController::class,
    )->middleware('signed')->name('login:store');
});

 

ما می خواهیم از یک کنترلر برای این route استفاده کنیم و اطمینان حاصل کنیم که میدلور امضا شده را اضافه کرده ایم. حالا می رویم به کنترلر نگاه می کنیم تا ببینیم چگونه URL های امضا شده را مدیریت می کنیم.

 

final class LoginController
{
    public function __invoke(Request $request, string $email): RedirectResponse
    {
        if (! $request->hasValidSignature()) {
            abort(Response::HTTP_UNAUTHORIZED);
        }
 
        /**
         * @var User $user
         */
        $user = User::query()->where('email', $email)->firstOrFail();
 
        Auth::login($user);
 
        return new RedirectResponse(
            url: route('dashboard:show'),
        );
    }
}

 

اولین قدم ما این است که اطمینان حاصل کنیم که URL دارای امضای معتبر است و اگر اینطور نباشد، یک پاسخ غیرمجاز ارسال کنیم. هنگامی که از معتبر بودن امضا مطمئن شدیم، می‌توانیم از کاربر ارسال شده پرس و جو کرده و آن را احراز هویت کنیم. در نهایت ریدایرکت redirect می کنیم به داشبورد.

 

خب کاربر ما اکنون با موفقیت وارد شده است و تا اینجا درست رفتیم .سپس ، ما باید مسیر ثبت نام را نیز بررسی کنیم. در ادامه این مسیر را اضافه می کنیم.

 

Route::middleware(['guest'])->group(static function (): void {
    Route::view('login', 'app.auth.login')->name('login');
    Route::get(
        'login/{email}',
        LoginController::class,
    )->middleware('signed')->name('login:store');
 
    Route::view('register', 'app.auth.register')->name('register');
});

 

مجدداً، ما از یک کامپوننت livewire برای فرم ثبت نام استفاده می کنیم - درست مانند کاری که با فرآیند ورود انجام دادیم.

 

 

final class RegisterForm extends Component
{
    public string $name = '';
 
    public string $email = '';
 
    public string $status = '';
 
    public function submit(CreateNewUser $user, SendLoginLink $action): void
    {
        $this->validate();
 
        $user = $user->handle(
            name: $this->name,
            email: $this->email,
        );
 
        if (! $user) {
            throw ValidationException::withMessages(
                messages: [
                    'email' => 'Something went wrong, please try again later.',
                ],
            );
        }
 
        $action->handle(
            email: $this->email,
        );
 
        $this->status = 'An email has been sent for you to log in.';
    }
 
    public function rules(): array
    {
        return [
            'name' => [
                'required',
                'string',
                'min:2',
                'max:55',
            ],
            'email' => [
                'required',
                'email',
            ]
        ];
    }
 
    public function render(): View
    {
        return view('livewire.auth.register-form');
    }
}

 

 

ما به جای استفاده مجدد از درخواست سشن ، نام، آدرس ایمیل، و یک ویژگی وضعیت داریم. دوباره  برای برگرداندن قوانین اعتبارسنجی برای این درخواست استفاده می کنیم. به روش ارسال برمی گردیم که این بار می خواهیم دو تا action تزریق کنیم.

 

CreateNewUser اقدامی است که ما برای ایجاد و بازگشت یک کاربر جدید بر اساس اطلاعات ارائه شده استفاده می کنیم. اگر به دلایلی این کار انجام نشد، یک استثنای اعتبارسنجی در ایمیل می‌زنیم. سپس از عمل SendLoginLink که در فرم ورود استفاده کردیم برای به حداقل رساندن تکرار کد استفاده می کنیم.

 

final class CreateNewUser
{
    public function handle(string $name, string $email): Builder|Model
    {
        return User::query()->create([
            'name' => $name,
            'email' => $email,
        ]);
    }
}

 

ما می‌توانیم نام route ورود به سیستم را تغییر دهیم، اما از نظر فنی این همان کاری است که ما دوباره انجام می‌دهیم. ما یک کاربر ایجاد می کنیم. سپس می خواهیم کاربر را وارد کنیم.

این یکی از روش‌هایی است که می‌توانید برای اجرای احراز هویت بدون رمز عبور انجام دهید،بعدا می توانید خودتان بهبود ببخشید آن را.

#احراز_هویت #لاراول #بدون_رمز_عبور #Passwordless #laravel