تایید رمز عبور با استفاده از فرم درخواست Laravel

13 خرداد 1398, خواندن در 8 دقیقه

شاید دیده باشید که در بسیاری برنامه ها، در برخی بخش ها از شما خواسته می شود که رمز عبور خود را دوباره وارد کنید، تا به شما اجازه دهند به ادامه کار مورد نظر بپردازید.

برای مثال، بخش تغییر رمز عبور Twitter. برای تنظیم یک رمز عبور جدید، باید رمز عبور فعلی خود را نیز وارد کنید.

چنین استراتژی ای به عنوان یک بررسی دو مرحله ای عمل می کند، و به برنامه شما یک لایه امنیت اضافه می کند.

جدول محتویات:

  1. دانش اولیه در مورد فرم درخواست
  2. ساخت View
  3. ساخت فرم درخواست
  4. Controller Action
  5. راه اندازی Route
  6. اضافه کردن نیازمندی های آخر
  7. آزمایش

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

دانش اولیه در مورد فرم درخواست

فرم درخواست چیست ؟

بیایید با نگاهی به اسناد رسمی Laravel شروع کنیم.

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

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

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

فرم های درخواست همچنین به شما در تمیز نگه دااری Controller Action ها کمک می کنند.

به جای انداختن تمام اعتبار سنجی ها و حالت های مشروطه داخل یک Controller Action، بهتر است با استفاده از یک فرم درخواست همه چیز را بهینه سازی کنید.

و در نهایت، فرم های درخواست به نحوی به عنوان کامپوننت هایی برای فیلتر کردن درخواست ها، قبل از رسیدن آن ها به Controller Action عمل می کنند.

در این آموزش سریع، و از آنجایی که آموزش راه اندازی Laravel Authentication خارج از محدوده این آموزش است، فرض را بر این می گذاریم که شما آن را به طور راه اندازی شده دارید.

ساخت View

با راه اندازی صفحه ویرایش پروفایل کاربر شروع می کنیم.

دستور کاربردی artisan هیچ view ای تولید نمی کند، پس باید آن را به طور دستی بسازیم.

فایل resources/views/profile/edit.blade.php را بسازید و این کد را به آن اضافه کنید:

@extends('layouts.app')

@section('content')
<div class="container">
    @if (session('info'))
        <div class="row">
            <div class="col-md-12">
                <div class="alert alert-success alert-dismissible">
                    <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
                    {{ session('info') }}
                </div>
            </div>
        </div>        
    @elseif (session('error'))
        <div class="row">
            <div class="col-md-12">
                <div class="alert alert-danger alert-dismissible">
                    <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
                    {{ session('error') }}
                </div>
            </div>
        </div>
    @endif
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Update Profile</div>

                <div class="panel-body">
                    <form class="form-horizontal" method="POST" action="{{ route('profile.update', ['user' => $user]) }}">
                        {{ csrf_field() }}
                        {{ method_field('PUT') }}
                        <div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
                            <label for="name" class="col-md-4 control-label">Name</label>
                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control" name="name" value="{{ $user->name }}">

                                @if ($errors->has('name'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('name') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Password</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password">

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation">
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('current_password') ? ' has-error' : '' }}">
                            <label for="current-password" class="col-md-4 control-label">Current Password</label>

                            <div class="col-md-6">
                                <input id="current-password" type="password" class="form-control" name="current_password">

                                @if ($errors->has('current_password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('current_password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Update
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

صفحه ویرایش پروفایل ما بسیار ساده است.

به دنبال Flash Message های info و error می گردیم و آنها را برای کاربر به نمایش می گذاریم.

این صفحه، فیلد هایی برای name، password، password_confirmation و current_password دارد.

نحوه ای که ما می خواهیم این صفحه کار کند، این است که هرگاه کاربر تغییری ایجاد کرد، حتما باید فیلد current_password را نیز پر کند، تا دیتابیس به روز رسانی شوند.

فیلد های password و password_confirmation به کاربر اجازه می دهند که رمز عبور خود را تغییر دهد. اگر هر دو فیلد خالی باشند، رمز عبور فعلی کاربر حفظ شده، و هیچ تغییری به رمز عبور ذخیره شده او اعمال نمی شود.

نقش های اصلی در view ما password، password_confirmation و current_password هستند.

فیلد name نیز مثالی برای گسترش و اضافه کردن فیلد ها به پرونده شما است.

ساخت فرم درخواست

حال به حیاتی ترین بخش این آموزش می رویم.

این دستور را اجرا کنید تا یک فرم درخواست ایجاد کنید:

php artisan make:request UpdateProfile

دستور بالا فایلی به نام UpdateProfile.php در app/Http/Requests/ می سازد.

تمام تغییرات کد در این بخش، به این فایل اعمال می شوند.

اولین کاری که باید انجام دهیم، این است که قبل از تعیین کلاس، با این کد به Laravel’s Hash Facade یک نام مستعار بدهیم:

use Illuminate\Support\Facades\Hash;

سپس، از آنجایی که ما هیچ مجوز دهی ای داخل فرم درخواست خود انجام نمی دهیم، باید true را از متود authorize خود برگردانیم.

/**
 * Determine if the user is authorized to make this request.
 *
 * @return bool
 */
public function authorize()
{
    return true;
}

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

/**
 * Get the validation rules that apply to the request.
 *
 * @return array
 */
public function rules()
{
    return [
        'name' => 'required|string|max:255',
        'password' => 'nullable|required_with:password_confirmation|string|confirmed',
        'current_password' => 'required',
    ];
}

قوانین name و current_password به خوبی واضح اهستند.

قوانین password می گویند که رمز عبور با استفاده از confirmed تایید می شود.

همچنین بیانگر requied_with:password_confirmation است، که یعنی اگر کاربر یک رمز عبور فعلی را تایید کرد، باید یک رمز عبور دیگر نیز وارد کند.

این اعتبار سنجی ها هر بار که با نوشتن متنی در Controller Action درخواستی ارسال می کنیم، به طور خودکار بررسی می شوند.

آخرین کاری که باید انجام دهیم، این است که یک متود withValidator را بر روی درخواست تعریف کنیم.

/**
 * Configure the validator instance.
 *
 * @param  \Illuminate\Validation\Validator  $validator
 * @return void
 */
public function withValidator($validator)
{
    // checks user current password
    // before making changes
    $validator->after(function ($validator) {
        if ( !Hash::check($this->current_password, $this->user()->password) ) {
            $validator->errors()->add('current_password', 'Your current password is incorrect.');
        }
    });
    return;
 }

داخل متود withValidator، یک Hook به نام after اضافه کرده ایم. تابعی که که پس از اجرا شدن تمام مراحل اعتبار سنجی اجرا می شود.

داخل after، به سادگی رمز عبور وارد شده توسط کاربر را با رمز عبور موجود در دیتابیس مقایسه کرده ایم.

بخش $this->current_password به فیلد current_password مقدار دهی می کند، در حالیکه Laravel به ما اجازه می دهد که با استفاده از $this->user() به کاربر فعلی دسترسی داشته باشیم، تا $this->user()->password به ما رمز عبور فعلی کاربر که در دیتابیس ذخیره شده است را بدهد.

این دو رمز عبور با استفاده از متود check نمای Hash مقایسه می شوند.

اگر این بررسی ناموفق باشد، یک خطا با کلید current_password و با استفاده از $validator->errors()->add('current_password', 'Your current password is incorrect.') به اعتبار سنج اضافه می شود.

در اینجا، فرم UpdateProfile را به طور کامل مشاهده می کنید:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

use Illuminate\Support\Facades\Hash;

class UpdateProfile extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name' => 'required|string|max:255',
            'password' => 'nullable|required_with:password_confirmation|string|confirmed',
            'current_password' => 'required',
        ];
    }

    /**
     * Configure the validator instance.
     *
     * @param  \Illuminate\Validation\Validator  $validator
     * @return void
     */
    public function withValidator($validator)
    {
        // checks user current password
        // before making changes
        $validator->after(function ($validator) {
            if ( !Hash::check($this->current_password, $this->user()->password) ) {
                $validator->errors()->add('current_password', 'Your current password is incorrect.');
            }
        });
        return;
    }
}

Controller Action

برای استفاده از فرم درخواستمان، باید آن را در Controller Action بنویسیم.

این دستور را برای تولید کنترلر پروفایل اجرا کنید:

php artisan make:controller ProfileController

فایل app/Http/Controllers/ProfileController.php را باز کنید و این دستورات را به آن اضافه کنید:

public function __construct()
{
    $this->middleware('auth');
}

/**
 * Show the form for editing the specified resource.
 *
 * @param  \App\User  $user
 * @return \Illuminate\Http\Response
 */
public function edit(Request $request, User $user)
{
    // user
    $viewData = [
        'user' => $user,
    ];
    // render view with data
    return view('profile.edit', $viewData);
}

/**
 * Update the specified resource in storage.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \App\User  $user
 * @return \Illuminate\Http\Response
 */
public function update(UpdateProfile $request, User $user)
{
    // form data
    $data = $request->all();
    $user->update($data);
    return redirect(route('profile.edit', ['user' => $user]))
                ->with('info', 'Your profile has been updated successfully.');
}

ساختار این کنترلر پروفایل به میان افزار auth دستور می دهد که مطمئن شود کاربر قبل از ویرایش پروفایل خود، وارد (login) شده باشد.

اکشن edit، داده های view را برای آن view فراهم می کند، در حالی که اکشن Update پروفایل کاربر را به روز رسانی می کند و او را به صفحه ویرایش می فرستد، و Flash Message متناظر را نشان می دهد.

به اثر اکشن edit در جایی که درخواست UpdateProfile را نوشته ایم دقت کنید. این تمام چیزی است که برای راه اندازی اعتبار سنجی داخل فرم درخواست UpdateProfile نیاز داریم.

همچنین باید قبل از تعریف کلاس Controller، به User Model و فرم درخواست، نام مستعار بدهیم.

use App\Http\Requests\UpdateProfile;
use App\User;

راه اندازی Route

فایل app/routes/web.php را باز کنید و این کد را به آن اضافه کنید:

Route::get('/profile/{user}/edit', '[email protected]')->name('profile.edit');
Route::put('/profile/{user}', '[email protected]')->name('profile.update');

اضافه کردن نیازمندی های آخر:

بر اساس قوانین اعتبار سنجی که پیش تر به فرم درخواست اضافه کردیم، رد شدن یک رمز عبور null (خالی) نیز ممکن است.

یک کاربر (یا یک توسعه دهنده برنامه) در هیچ شرایطی نمی خواهد که رمز عبورش خالی باشد.

برای این که مطمئن شویم رمز عبور فقط در صورت پر بودن تعیین می شود، از Eloquent ORM’s mutators استفاده می کنیم.

فایل app/User.php را باز کنید و این کد را به آن اضافه کنید:

// Only accept a valid password and 
// hash a password before saving
public function setPasswordAttribute($password)
{
    if ( $password !== null & $password !== "" )
    {
        $this->attributes['password'] = bcrypt($password);
    }
}

Eloquent mutator ها باید از این حالت نام پشتیبانی کنند:

set<camel-cased-attribute-name>Attribute

از آنجایی که در حال تعریف یک mutator برای صفت password هستیم، نام mutator را setPasswordAttribute قرار می دهیم.

ما در mutator خود، تنها بررسی می کنیم که متغیر $password خالی نباشد، و آن را با استفاده از $this->attributes[‘password’] بر روی model خود قرار می دهیم.

همچنین دقت کنید که رمز عبور قبل از ذخیره شدن خرد شده است، تا بعدا و در جای دیگری از برنامه مجبور به انجام این کار نشویم.

در Laravel به طور پیشفرض Auth/RegisterController و Auth/ResetPasswordController نیز رمز عبور را قبل از ذخیره سازی در دیتابیس خرد می کنند، پس باید پس از تعریف mutator بالا، متود های create و resetPassword خود را به روز رسانی کنیم.

فایل app/Http/Controllers/Auth/RegisterController.php را باز کنید و این کد را به آن اضافه کنید:

/**
 * Create a new user instance after a valid registration.
 *
 * @param  array  $data
 * @return \App\User
 */
protected function create(array $data)
{
    return User::create([
        'name' => $data['name'],
        'email' => $data['email'],
        'password' => $data['password'],
    ]);
}

حال فایل app/Http/Controllers/Auth/ResetPasswordController.php را باز کنید و این کد را به آن اضافه کنید:

/**
 * Reset the given user's password.
 *
 * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
 * @param  string  $password
 * @return void
 */
protected function resetPassword($user, $password)
{
    $user->password = $password;

    $user->setRememberToken(Str::random(60));

    $user->save();

    event(new PasswordReset($user));

    $this->guard()->login($user);
}

برای ResetPasswordController، باید به کلاس های respective نیز قبل از تعریف کلاس اصلی نام مستعار بدهید:

use Illuminate\Support\Str;
use Illuminate\Auth\Events\PasswordReset;

آزمایش

کار ما تمام شده، و تایید رمز عبور ما همانطور که انتظار می رفت، کار می کند.

یک بار آزمایش برنامه با رمز عبور اشتباه یا خالی، صفحه ای مانند صفحه موجود در این اسکرین شات ها را نشان می دهد:

لاراوللاراول

حال به نظر شما، آیا راه بهتری برای انجام این کار در Laravel وجود دارد؟

امیدوارم این مقاله برایتان کاربردی بوده باشد.

منبع

چه امتیازی به این مقاله می دید؟
خیلی بد
بد
متوسط
خوب
عالی

دیدگاه‌ها و پرسش‌ها

برای ارسال دیدگاه لازم است، ابتدا وارد سایت شوید.

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

آفلاین
user-avatar
عرفان کاکایی @er79ka
دنبال کردن

گفتگو‌ برنامه نویسان

بخشی برای حل مشکلات برنامه‌نویسی و مباحث پیرامون آن وارد شو