+1

Login nhanh chóng với Trait AuthenticatesUsers Laravel

Hi, xin chào mọi người.

Giới thiệu một chút mình đang làm dev laravel nha. Cảm hứng mình viết bài viết này là từ lúc mình đang làm lại 1 chức năng mà chắc ai dev cũng chắc chắn làm qua rồi, đó chính là chức năng login. Chia sẻ 1 chút, cá nhân mình cũng mày mò nghiên cứu nên thời gian đầu cho đến lúc viết bài viêt này mình cũng gà lắm.

Kể về thời điểm trước đây khi mình làm chức năng login, minh cũng loay hoay lắm, nào là add package Laravel Breeze, rồi Laravel Jetstream xong rồi không biết làm thế nào để sửa lại giao diện cho giông với template mình muốn. Xong rồi cũng lại remove package đi tại vì còn gà , xong thiết kế lại theo template cho đẹp rồi thì lại ko biết xử lý sao cho phần login (lúc đó mình chỉ validation các trường nhập vào, rồi dùng attempt để check email, password). Rồi còn lấy ra user xong check điều kiện khác để login ngoài 2 trường email và password (kiểm tra user có active hay ko đó).

Nhưng rồi, vào 1 ngày tình cờ và thật bất ngờ, mình có lười 1 chút khi suy nghĩ là giờ làm thế nào cho nhanh chứ ngồi code lại cái login này mất thời gian quá (lúc đó mình đang làm chức năng khác 😁 ), Rồi câu chuyện bắt đầu từ đây, mình lên ChatGpt và Google tìm kiếm giải pháp và có kiếm ra đc từ khóa AuthenticatesUsers. Rồi luôn đọc vào code cái trait cái tự dưng khai mở luôn. Bắt đầu nhé.

dùng trait AuthenticatesUsers cho LoginController

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    use AuthenticatesUsers;

    // Bạn có thể thêm các tùy chỉnh tại đây
}

Đi sâu vào trong trait này, mn sẽ thấy nó đã xử lý đầy đủ mọi thứ liên quan đến login:

<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

trait AuthenticatesUsers
{
    use RedirectsUsers, ThrottlesLogins;

    /**
     * Show the application's login form.
     *
     * @return \Illuminate\View\View
     */
    public function showLoginForm()
    {
        return view('auth.login');
    }

    /**
     * Handle a login request to the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function login(Request $request)
    {
        $this->validateLogin($request);

        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if (method_exists($this, 'hasTooManyLoginAttempts') &&
            $this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        if ($this->attemptLogin($request)) {
            if ($request->hasSession()) {
                $request->session()->put('auth.password_confirmed_at', time());
            }

            return $this->sendLoginResponse($request);
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }

    /**
     * Validate the user login request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return void
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    protected function validateLogin(Request $request)
    {
        $request->validate([
            $this->username() => 'required|string',
            'password' => 'required|string',
        ]);
    }

    /**
     * Attempt to log the user into the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return bool
     */
    protected function attemptLogin(Request $request)
    {
        return $this->guard()->attempt(
            $this->credentials($request), $request->boolean('remember')
        );
    }

    /**
     * Get the needed authorization credentials from the request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password');
    }

    /**
     * Send the response after the user was authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
     */
    protected function sendLoginResponse(Request $request)
    {
        $request->session()->regenerate();

        $this->clearLoginAttempts($request);

        if ($response = $this->authenticated($request, $this->guard()->user())) {
            return $response;
        }

        return $request->wantsJson()
                    ? new JsonResponse([], 204)
                    : redirect()->intended($this->redirectPath());
    }

    /**
     * The user has been authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  mixed  $user
     * @return mixed
     */
    protected function authenticated(Request $request, $user)
    {
        //
    }

    /**
     * Get the failed login response instance.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    protected function sendFailedLoginResponse(Request $request)
    {
        throw ValidationException::withMessages([
            $this->username() => [trans('auth.failed')],
        ]);
    }

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

    /**
     * Log the user out of the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
     */
    public function logout(Request $request)
    {
        $this->guard()->logout();

        $request->session()->invalidate();

        $request->session()->regenerateToken();

        if ($response = $this->loggedOut($request)) {
            return $response;
        }

        return $request->wantsJson()
            ? new JsonResponse([], 204)
            : redirect('/');
    }

    /**
     * The user has logged out of the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return mixed
     */
    protected function loggedOut(Request $request)
    {
        //
    }

    /**
     * Get the guard to be used during authentication.
     *
     * @return \Illuminate\Contracts\Auth\StatefulGuard
     */
    protected function guard()
    {
        return Auth::guard();
    }
}

Và đây, chỉ cần override lại function attemptLogin tại LoginController thì mình đã giải quyết được việc thêm các điều kiện check khác khi login (account active hay ko) mà trong khi chỉ có 2 trường nhập vào là email và password

<?php

namespace App\Http\Controllers\Client\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/';

    public function __construct()
    {
        $this->middleware('guest:web')->except('logout');
    }

    protected function guard()
    {
        return Auth::guard('web');
    }

    public function showLoginForm()
    {
        return view('auth.client.login');
    }

    protected function attemptLogin(Request $request)
    {
        return $this->guard()->attempt(
            [
                'email' => $request->email,
                // 'username' => $request->username,  // Nếu muốn sử dụng cả email và username
                'password' => $request->password,
                'is_active' => User::STATUS_ACTIVE,  // Chỉ cho phép người dùng có is_active active đăng nhập
                'is_verify' => User::VERIFY,  // Chỉ cho phép người dùng có is_verify active đăng nhập
            ],
            $request->boolean('remember')
        );
    }

    protected function sendFailedLoginResponse(Request $request)
    {
        $user = User::where('email', $request->input('email'))->first();

        if ($user) {
            if ($user->is_active !== User::STATUS_ACTIVE) {
                throw ValidationException::withMessages([
                    'email' => [trans('auth.not_active')],  // Thông báo cho tài khoản không active
                ]);
            }
            // Bạn có thể kiểm tra thêm điều kiện khác ở đây
        }

        throw ValidationException::withMessages([
            'email' => [trans('auth.failed')],  // Thông báo lỗi chung
        ]);
    }
}

Còn rất nhiều trait khác trong Laravel có tích hợp để register, forgot password, bla bla,.. Mọi người cũng nên hỏi các tool open ai nha, nhiều khi 1 vấn đề mình ngâm rất lâu, chỉ hỏi nó 1,2 câu là ra vấn đề ngay đó. Ai mạnh quá rồi. Cảm ơn mọi người đã đọc đến đây. Chúc mọi người thành công!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí