Laravel: Tùy biến chức năng Authentication mặc định của Laravel

Mở đầu

Như chúng ta đều biết (và đều sử dụng rồi) Laravel có một bộ công cụ vô cùng mạnh mẽ gần như bao trọn gói nhu cầu tạo dựng một website từ đơn giản đến khá phức tạp. Và công cụ quan trọng nhất mà chắc chắn ai trong chúng ta cũng đã từng sử dụng đó là Authentication (default).

Chỉ cần một command đơn giản là: php artisan make:auth là form đăng nhập của bạn đã sẵn sàng để sử dụng. Nhưng trong bài viết này, hãy thử khám phá sâu hơn chút nữa vào chức năng này và có thể là tự tùy biến thêm bớt hay thay đổi một số tính năng mặc định của nó mà bạn có thể thích hoặc không thích sử dụng.

Ai chưa biết thì nhớ Like + Upvote + Subscribes + Share cho bé

Ai biết rồi thì ném đá nhẹ tay để bé còn giữ mồm ăn tết ạ 😄

Lưu ý: Phiên bản Laravel được sử dụng trong bài viết là Laravel 5.7.*

1. Tắt chức năng đăng ký:

Vì một lý do nào đó mà bạn không muốn người ngoài tọc mạch sử dụng chức năng đăng ký hoặc đơn giản là bạn muốn tự tay cấp tài khoản cho từng user vì hệ thống của bạn là một hệ thống cần độ bảo mật cao chẳng hạn, bạn có thể thêm dòng code sau vào file routes/web.php:

Auth::routes(['register' => false]);

Sau khi thực hiện việc này, bất cứ truy cập nào vào /register sẽ trả ra page 404

2. Bật tính năng xác thực Email:

Từ phiên bản 5.7 trở đi, Laravel đã cung cấp sẵn luôn tính năng xác thực Email.

Đầu tiên bạn cần thêm vào bảng users của mình cột email_verified_at, sau đó bạn mở file routes/web.php và thêm dòng lệnh sau để bật tính năng này:

Auth::routes(['verify' => true]);

Tiếp theo chạy lệnh php artisan make:auth để tạo một views xác thực cho người dùng khi họ click vào đường link xác thực trong email.

Bonus: Bạn có thể xác thực sâu hơn, cho phép chỉ những người dùng đã xác thực email mới có thể xem các tính năng mà bạn cho phép như sau:

Route::get('profile', function () {
    // chỉ những tài khoản đã xác thực email mới được sử dụng các chức năng bị giới hạn bởi middleware
})->middleware('verified');

3. Tắt chức năng đặt lại mật khẩu

Khi bạn chạy php artisan make:auth, các views Login, Register, Forgetten Password cũng sẽ mặc định được tạo theo. Vì một lý do nào đó mà bạn muốn tắt chức năng này đi thì bạn có thể thêm dòng sau vào routes/web.php:

Auth::routes(['reset' => false]);
Note nhỏ: bạn hoàn toàn có thể gộp tất cả 3 tính năng ở trên bằng một lệnh duy nhất:
Auth::routes([
  'register' => false,
  'verify' => true,
  'reset' => false
]);

4. Chuyển hướng trang sau khi đăng nhập:

Mặc định Laravel sẽ chuyển hướng trang đăng ký sang trang /home sau khi bạn đăng ký thành công tài khoản. Nếu bạn muốn chuyển sang trang khác, ví dụ trang profile chẳng hạn, thì bạn có thể thay đổi trong app/Http/Controllers/Auth/RegisterController.php :

class RegisterController extends Controller
{
    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
     // đổi cái này thành route mà bạn mong muốn
    protected $redirectTo = '/home';

Đó là cách dễ, giả sử bạn muốn làm một số thứ phức tạp hơn, như là kiểm tra xem thằng user đó có phải là admin không, để cho nó vào luôn trang /admin chẳng hạn. Bạn có thể thực hiện điều này bằng cách tạo một phương thức có tên redirectTo() :

protected function redirectTo()
{
    if (auth()->user()->role_id == 1) {
        return '/admin';
    }
    return '/home';
}

Phương thức này sẽ ghi đè thuộc tính $redirectTo và chuyển hướng trang theo đúng logic bạn mong muốn.

5. Thay đổi ràng buộc dữ liệu:

Auth mặc định đã đặt ràng buộc cho các trường dữ liệu

  • name
  • email
  • password
  • confirm password

Nhưng nếu bạn muốn thay đổi lại một số ràng buộc theo nhu cầu của bản thân, hoặc bỏ một số ràng buộc thì bạn có thể sửa lại phương thức validator trong app/Http/Controllers/Auth/RegisterController.php:

protected function validator(array $data)
{
    return Validator::make($data, [
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => ['required', 'string', 'min:6', 'confirmed'],
    ]);
}

6. Tắt chức năng tự động đăng nhập sau khi đăng ký thành công:

Đây có lẽ là một trong những tính năng mình rất hay bỏ đi khi làm login, vì đơn giản mình muốn user sau khi đăng ký cần phải trải qua một lần đăng nhập để chắc chắn là người đó đang dùng tài khoản chính chủ 😄 hoặc cho mục đích xác thực email bla bla

Để thực hiện điều này, bạn cần phải ghi đè phương thức register() trong trait RegistersUsers.

Nếu bạn không biết thì nó được nhắc đến trong RegisterController:

class RegisterController extends Controller
{
    use RegistersUsers;

Dùng editor PHP Storm bạn sẽ tìm được file này tại vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.php:

trait RegistersUsers
{
    /**
     * Handle a registration request for the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request)
    {
        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));

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

        return $this->registered($request, $user)
                        ?: redirect($this->redirectPath());
    }

    // ...

}

Việc cần làm bây giờ là xóa bỏ dòng $this->guard()->login($user), nhưng cơ bản là chúng ta không thể sửa các file nằm trong vendor được, nên chúng ta sẽ phải tạo một phương thức register ghi đè lên phương thức registẻ kia. Bạn mở RegisterController:

namespace App\Http\Controllers\Auth;

// Nhớ thêm 2 dòng này vào
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Registered;

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;

class RegisterController extends Controller
{

    // ...

    /**
     * Handle a registration request for the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request)
    {
        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));
        // ở đây đã xóa dòng $this->guard()->login($user)
        return $this->registered($request, $user)
            ?: redirect($this->redirectPath());
    }

}

Cuối cùng nhớ kiểm tra lại thuộc tính $redirectTo để chắc chắn trang sẽ được redirect đến route bạn mong muốn.

7. Thêm các trường dữ liệu khác vào Form Đăng ký:

Ngoài các trường dữ liệu mặc định của chức năng đăng ký là name, email, password chúng ta có thê thêm các trường dữ liệu khác cho mỗi user, ví dụ như phone chẳng hạn. Cách làm như sau:

Thêm một cột tên phone vào bảng users, tất nhiên chúng ta sẽ tạo một file migration alter_table_users_add_phone để migrate cột này vào.

$table->string(‘surname’)

Sửa lại model User, thêm phone vào:

protected $fillable = [
    'name', 'email', 'password', 'phone'
];

Thêm input phone nhập để nhập dữ liệu trong view resources/views/auth/register.blade.php:

<div class="form-group row">
    <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Phone') }}</label>

    <div class="col-md-6">
        <input id="phone" type="text" class="form-control{{ $errors->has('phone') ? ' is-invalid' : '' }}" name="phone" value="{{ old('phone') }}" required autofocus>

        @if ($errors->has('phone'))
            <span class="invalid-feedback" role="alert">
                <strong>{{ $errors->first('phone') }}</strong>
            </span>
        @endif
    </div>
</div>

Sửa lại phương thức create():

protected function create(array $data)
{
    return User::create([
        'name' => $data['name'],
        //thêm dòng này nứa 
        'phone' => $data['phone'],
        'email' => $data['email'],
        'password' => Hash::make($data['password']),
    ]);
}

8. Đăng nhập bằng Username thay vì Email:

Trong một số trường hợp bạn sẽ mong muốn chức năng đăng nhập của mình sẽ sử dụng Username thay vì Email như mặc định của Laravel, dưới đây là cách chuyển đổi để làm điều đó.

Hãy nhìn qua một chút về cấu trúc của LoginController, bạn sẽ thấy nó đang use một trait có tên là AuthenticatesUsers, dùng PHP Storm và nhìn qua một chút về trait này /vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php:

Bạn sẽ nhìn thấy một phương thức có tên là username()

/**
 * Get the login username to be used by the controller.
 *
 * @return string
 */
public function username()
{
    return 'email';
}

Đọc qua comment bạn có thể hiểu, phương thức này trả về một giá trị duy nhất chính là tên của trường dữ liệu tương ứng trong view và trong database cũng như model User, giá trị này dùng để xác thực tên tài khoản người dùng, vậy nên bạn muốn chuyển qua dùng username thì chỉ cần sửa lại thành return 'username'; là được, nhưng rõ ràng trait này nằm trong phần core của Laravel nên bạn không thể sửa đổi nó, thay vào đó hãy tạo một phương thức username() trong LoginController để ghi đè lên phương thức này:

LoginController:

class LoginController extends Controller
{
    use AuthenticatesUsers;
    // ...

    public function username()
    {
        return 'username';
    }
}

Lời kết

Đó là một số thay đổi nhỏ giúp bạn tùy biến linh hoạt hơn chức năng cơ bản nhất mà Laravel cung cấp.

Cám ơn các bạn đã theo dõi bài viết!