PHP

Laravel 5.8: Tìm hiểu về Authentication

Bài này chúng ta sẽ cùng tìm hiểu về cách sử dụng Authentication trong laravel 5.8 nhé. 😃

Introduction

Laravel giúp cho việc thực hiện việc xác thực vô cùng đơn giản. Trong thực tế, hầu hết mọi thứ đã được cấu hình cho bạn mà bạn đéo thể tưởng tượng nổi (out of the box). Các file cấu hình xác thực được đặt tại config/auth.php, bao gồm một số hướng dẫn tùy biến rõ ràng cho việc tinh chỉnh cách xử lí của các dịch vụ authentication.

Tại phần lõi của nó, các cơ sở của Laravel's authentication được tạo bởi các "guards" và "providers". Guards định nghĩa cái cách mà các user được xác thực cho mỗi request. Ví dụ, Laravel mang theo một session guard cái mà duy trì trạng thái bằng cách sử dụng session storage và cookies và một token guard, cái mà xác thực user bằng cách sử dụng một "API token" cái mà được truyền cùng mỗi request.

Providers định nghĩa cách mà user được truy xuất từ lưu trữ không đổi (persistent storage) của bạn. Laravel hỗ trợ cho việc truy xuất các user sử dụng Eloquent và Query Builder.

Database Considerations

Mặc định, Laravel bao gồm một Eloquent model App\User trong thư mục app. Model này có thể sử dụng với Eloquent authentication driver mặc định.

Khi xây dựng database schema cho model App\User, đảm bảo rằng độ dài cột password tối thiểu là 60 kí tự, mặc định với 255 kí tự.

Bạn cũng nên xác nhận table user ( hoặc một table khác tương đương ) gồm một giá trị nullable, cột remember_token 100 kí tự. Cột này sẽ được dùng để lưu một token cho session "remember me" khi đang được duy trì bởi ứng dụng của bạn.

Authentication Quickstart

Laravel mang tới 2 authentication controllers tuyệt vời, được đặt trong namespace App\Http\Controllers\Auth. RegisterController được sử dụng để đăng ký người dùng mới. ForgotPasswordController xử lý các liên kết email để đặt lại mật khẩu và ResetPasswordController kiểm chứa logic để đặt lại mật khẩu. Mỗi bộ điều khiển này sử dụng một đặc điểm để bao gồm các phương thức cần thiết của chúng. Đối với nhiều ứng dụng, bạn sẽ không cần phải sửa đổi các bộ điều khiển này.

Routing

Laravel cung cấp một cách nhanh chóng để sinh ra toàn bộ các route và view cần thiết cho authentication chỉ với 1 command:

    php artisan make:auth

Command này nên được dùng trên các ứng dụng mới và sẽ cài đặt các view đăng kí và đăng nhập cũng như các route cho toàn bộ việc xác thực đầu cuối. Một HomeController cũng sẽ được sinh ra, phục vụ các request post-login tới ứng dụng. Tuy nhiên, bạn có thể tự do tùy chỉnh hoặc xóa controller này dựa trên sự cần thiết trong ứng dụng của bạn.

Views

Như đã đề cập ở phần trên, command php artisan make:auth cũng sẽ tạo toàn bộ các view cần thiết cho việc xác thực và đặt chúng trong thư mục resources/views/auth.

Command make:auth cũng tạo một thư mục resources/views/layouts bao gồm các layout cơ bản cho ứng dụng. Toàn bộ những view này sử dụng framework Bootstrap CSS, nhưng bạn tự do tùy chỉnh nếu bạn thích.

Authenticating

Bây giờ bạn có các route và view chuẩn bị cho các authentication controllers, bạn đã sẵn sàng để đăng kí và xác nhận những user mới cho ứng dụng. Bạn chỉ đơn giản truy cập ứng dụng thông qua trình duyệt. Các authentication controller đã sẵn sàng gồm các logic (thông qua trait của chúng) để xác nhận những user đã tồn tại và lưu những user mới vào database.

Path Customization

Khi một user được xác nhận thành công, họ sẽ được chuyển sang URI '/'. Bạn có thể tùy biến địa chỉ chuyển hướng post-authentication bằng cách định nghĩa thuộc tính redirectTo trong LoginController, RegisterController, ResetPasswordController &VerificationController:

    protected $redirectTo = '/';

Tiếp theo, bạn có thể sửa đổi RedirectIfAuthenticated middleware's để xử lý chuyển hướng người dùng

Nếu đường dẫn chuyển hướng cần logic cần tùy chỉnh, bạn có thể xác định phương thức redirectTo thay vì thuộc tính redirectTo:

protected function redirectTo()
{
    return '/path';
}

Username Customization

Bởi mặc định, Laravel sử dụng email cho authentication.Nếu bạn muốn tùy chỉnh bạn có thể định nghĩa username method trong LoginController:

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

Guard Customization Bạn cũng có thể tùy biến "guard" cái mà sử dụng để xác thực user. Để bắt đầu, định nghĩa một thuộc tính guard trong LoginController, RegisterController, and ResetPasswordController. Phướng thức sẽ trả về một thể hiện của guard.

use Illuminate\Support\Facades\Auth;

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

Validation / Storage Customization

Để thay đổi các trường trong form được yêu cầu khi người dùng đăng kí với ứng dụng của bạn, hoặc tùy biến các bản ghi user mới được chèn vào database như thế nào, bạn có thể chỉnh sửa class RegisterController. Class này chịu trách nhiệm việc valite và tạo user mới của ứng dụng.

Phương thức validator của RegisterController bao gồm các luật validate cho user mới của ứng dụng. Bạn hoàn toàn tự do tùy chỉnh các phương thức này nếu bạn muốn.

Phương thức create của RegisterController chịu trách nhiệm cho việc tạo bản ghi mới App\User trong database sử dụng . Bạn tự do chỉnh sửa những phương thức này cho phù hợp database.

Retrieving The Authenticated User

Bạn có thể truy cập người dùng đã được xác thực thông qua facade Auth:

use Illuminate\Support\Facades\Auth;

// Get the currently authenticated user...
$user = Auth::user();

// Get the currently authenticated user's ID...
$id = Auth::id();

Ngoài ra, mội khi user đã được xác thực, bạn có thể truy cập thông qua môt instance Illuminate\Http\Request. Hãy nhớ, các class gợi ý sẵn sẽ tự động được thêm vào trong các phương thức của controller:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProfileController extends Controller
{
    /**
     * Update the user's profile.
     *
     * @param  Request  $request
     * @return Response
     */
    public function update(Request $request)
    {
        // $request->user() returns an instance of the authenticated user...
    }
}

Kiểm tra việc xác thực của User

Để xác định user đã đăng nhập vào ứng dụng của bạn hay chưa, bạn có thể sử dụng phương thức check trên face Auth, cái mà sẽ trả về true nếu user đã được xác thực:

    if (Auth::check()){
        // The user is logged in...
    }

Protecting Routes

Route middlewarecó thể được sử dụng để cho phép chỉ những user đã được xác thực truy cập vào các route đã cho. Laravel mang tới middleware auth, cái mà được định nghĩa trong app\Http\Middleware\Authenticate. Toàn bộ những gì bạn cần là đính kèm middleware vào định nghĩa (khai báo) của route.


Route::get('profile', function () {
    // Only authenticated users may enter...
})->middleware('auth');

If bạn sử dụng controller, bạn có thể gọi phương thức middleware từ contructor của controller thay vì đính kèm nó

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

Redirecting Unauthenticated Users

Khi đính kèm middleware auth vào một route, bạn cũng có thể chỉ định guard nào sẽ được dùng để thực thi việc xác thực, login named route. Bạn có thể tùy chỉnh redirectTo function trong app/Http/Middleware/Authenticate.php file:

/**
 * Get the path the user should be redirected to.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return string
 */
protected function redirectTo($request)
{
    return route('login');
}

Specifying A Guard

Guard được chỉ định nên tương ứng với một trong các key trong mang guards của file cấu hình auth.php.

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

Login Throttling

Nếu bạn đang sử dụng lớp LoginController được tích hợp trong Laravel, Illuminate\Foundation'Auth\ThrottlesLogins trait có thể được dùng để điều chỉnh các nỗ lực đăng nhập vào ứng dụng của bạn. Mặc định, người dùng sẽ không thể đăng nhập trong 1 phút nếu họ thất bại trong việc cung cấp thông tin chính xác một vài lần. Việc điều phối (throttling) này là duy nhất với một username / e-mail và địa chỉ IP của họ:

##Manually Authenticating Users

Tất nhiên, bạn không bắt buộc phải sử dụng các authentication controller trong Laravel. Nếu bạn lựa chọn xóa những controller này, bạn sẽ cần phải quản lí việc xác thực user bằng cách sử dụng các class Laravel xác thực trực tiếp. Đừng lo lắng, nó là chắc chắn rồi!

Chúng ta sẽ truy cập vào các Laravel's authentication services thông qua facade Auth, vì vậy chúng ta cần đảm bảo import facade Auth tại đầu class. Tiếp theo, hãy kiểm tra phương thức attempt:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    /**
     * Handle an authentication attempt.
     *
     * @param  \Illuminate\Http\Request $request
     *
     * @return Response
     */
    public function authenticate(Request $request)
    {
        $credentials = $request->only('email', 'password');

        if (Auth::attempt($credentials)) {
            // Authentication passed...
            return redirect()->intended('dashboard');
        }
    }
}

Phương thức attempt chấp nhận một mảng các cặp key / value như là tham số đầu tiên. Các giá trị trong mảng sẽ được dùng để tìm user trong database. Vì vậy trong ví dụ trên, user sẽ được lấy ra bởi giá trị của cột email. Nếu tìm thấy user, hashed password được lưu trong database sẽ được dùng để so sánh với giá trị hashed password mà được truyền vào phương thức thông qua mảng. Nếu 2 hashed passowrd trùng hợp, một session sẽ được bắt đầu cho user.

Phương thức attemp sẽ trả về true nếu xác thực thành công. Ngược lại là false.

Phương thức intended trên redirector sẽ chuyển hướng user tới URL họ vừa cố gắn truy cập trước khi bị bắt bởi authentication filter. Một fallback URI có thể được cho trước vào phương thức này trong trường hợp đích đến dự kiến không có.

Specifying Additional Conditions

Nếu muốn, bạn cũng có thể thêm những điều kiện mở rộng vào truy vấn xác thực. Ví dụ, chúng ta có thể xác nhận xem user đã được đánh dấu như "active":

    if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
        // The user is active, not suspended, and exists.
   }

Accessing Specific Guard Instances

Bạn có thể chỉ định các guard instance bạn thích để làm việc bằng cách dùng phương thức guard trên facade Auth. Điều này cho phép bạn quản lí việc xác thực cho những thành phần khác nhau trong ứng dụng bằng cách sử dụng trọn vẹn các model có khả năng xác thực tách biệt hoặc các table user.

Tên của guard truyền vào phương thức guard nên tương ứng với một trong các guard được cấu hình trong file auth.php:

    if (Auth::guard('admin')->attempt($credentials)) {
        //
    }

Logging Out

Để đăng xuất người dùng khỏi ứng dụng của bạn, bạn có thể sử dụng phương thức logout trên facade Auth. Việc này sẽ xóa toàn bộ thông tin xác thực trong session của user:

    Auth::logout();

Remembering Users

Nếu bạn muốn cung cấp chức năng "remember me" trong ứng dụng, bạn có thể truyền một giá trị boolean như tham số thứ 2 vào phương thức attempt, cái mà sẽ giữ cho người dùng đã được xác thực vô thời hạn, hoặc tới khi họ đăng xuất thủ công. Tất nhiên, table users phải có một cột tring remember_token, cái mà sẽ được dùng để lưu token "remember me".

    if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
        // The user is being remembered...
    }

Nếu bạn "remembering" người dùng, bạn có thể dùng phương thức viaRemember để xác định nếu user đã được xác thực bằng cách dùng cookie "remember me":

    if (Auth::viaRemember()) {
        //
    }

Other Authentication Methods

Nếu bạn cần đăng nhập một user instance đang tồn tại vào ứng dụng, bạn có thể gọi phương thức login với user instance. Đối tượng đã cho phải là một imlementation của Illuminate\Contracts\Auth\Authenticatable contract. Tất nhiên, model App\User của Laravel đã implement interface này rồi:

    Auth::login($user);

    // Login and "remember" the given user...
    Auth::login($user, true);

Tất nhiên, bạn có thể chỉ định guard instance bạn muốn sử dụng:

    Auth::guard('admin')->login($user);

Authenticate A User By ID

Để đăng nhập một user vào ứng dụng bằng ID của họ, bạn có thể sử dụng phương thức loginUsingId. Phương thức này chấp nhận primary key của của user bạn muốn để xác thực:

    Auth::loginUsingId(1);

    // Login and "remember" the given user...
    Auth::loginUsingId(1, true);

####Authenticate A User Once

Bạn có thể sử dụng phương thức once để đăng nhập một user vào ứng dụng cho một single request. Không có session hay cookie được tạo ra, cái có thể hữu ích khi xây dựng stateless API (khác với stateful API, stateless API không lưu trạng thái của từng người dùng truy cập vào ứng dụng). Phương thức once có cách dùng tương tự như phương thức attempt:

    if (Auth::once($credentials)) {
        //
    }

HTTP Basic Authentication

HTTP Basic Authentication cung cấp một cách nhanh chóng để xác thực người dùng của ứng dụng của bạn mà không cần phải thiết lập một trang "login" tách biệt. Để bắt đầu, đính kèm auth.basic middleware vào route của bạn. Middleware auth.basic được bao gồm trong Laravel framework, vì vậy bạn không cần phải định nghĩa nó:

    Route::get('profile', ['middleware' => 'auth.basic', function() {
        // Only authenticated users may enter...
    }]);

Một khi middleware đã được đính kèm vào route, bạn sẽ tự động được nhắc nhở về các thông tin khi truy cập vào route trên trình duyệt. Mặc định, middleware auth.basic sẽ dùng cột email trên các bản ghi user như là "username".

A Note On FastCGI

Nếu bạn đang sử dụng PHP FastCGI, HTTP Basic authentication có thể không hoạt động chính xác. Những dòng sau nên được thêm vào trong file .htaccess của bạn:

    RewriteCond %{HTTP:Authorization} ^(.+)$
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Stateless HTTP Basic Authentication

Bạn cũng có thể sử dụng HTTP Basic Authentication mà không cần thiết lập một cookie định danh người dùng trong session, cái mà là một thành phần hữu ích cho API authentication. Việc tiếp theo, Định nghĩa một middleware cái mà gọi phương thức onceBasic. Nếu không có response nào được trả về bởi phương thức onceBasic, request có thể được chuyển vào trong ứng dụng:

    <?php

    namespace Illuminate\Auth\Middleware;

    use Auth;
    use Closure;

    class AuthenticateOnceWithBasicAuth
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next)
        {
            return Auth::onceBasic() ?: $next($request);
        }

    }

Tiếp theo Đăng kí route middleware và đính kèm nó vào một route:

  Route::get('api/user', function () {
    // Only authenticated users may enter...
})->middleware('auth.basic.once');

Logging Out

Để đăng xuất khỏi ứng dụng method loguot của Auth facade

use Illuminate\Support\Facades\Auth;

Auth::logout();

Invalidating Sessions On Other Devices

Laravel cung cấp cơ chế vô hiệu hóa "logging out" một user sesion với các thiết bị khác. Trước khi bắt đầu, bạn nên chắc chắn rằng Illuminate\Session\Middleware\AuthenticateSession middlewarelà tham gia un-commented in your app/Http/Kernel.php class' web middleware group:

'web' => [
    // ...
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    // ...
],

Bạn có thể sử dung logoutOtherDevices method của Auth facade. Phương thức này yêu cầu user cung cấp pasword hiện tại, phần input vào từ form.

use Illuminate\Support\Facades\Auth;

Auth::logoutOtherDevices($password);

Adding Custom Guards

Bạn có thể định nghĩa các authentication guard của bạn bằng cách sử dụng phương thức extend trên facade Auth. Bạn nên đặt lời gọi này tới provider cùng với một provider:

    <?php

    namespace App\Providers;

    use Auth;
    use App\Services\Auth\JwtGuard;
    use Illuminate\Support\ServiceProvider;

    class AuthServiceProvider extends ServiceProvider
    {
        /**
         * Perform post-registration booting of services.
         *
         * @return void
         */
        public function boot()
        {
            Auth::extend('jwt', function($app, $name, array $config) {
                // Return an instance of Illuminate\Contracts\Auth\Guard...

                return new JwtGuard(Auth::createUserProvider($config['provider']));
            });
        }

        /**
         * Register bindings in the container.
         *
         * @return void
         */
        public function register()
        {
            //
        }
    }

Như bạn có thể thấy trong ví dụ trên, callback được truyền vào phương thức extend trả về một implementation của Illuminate\Contracts\Auth\Guard. Interface này bao gồm vài phương thức bạn sẽ cần để implement để định nghĩa một custom guard.

Một khi custom guard của bạn được định nghĩa, bạn có thể sử dụng guard trong cấu hình guards:

    'guards' => [
        'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
    ],

Adding Custom User Providers

Nếu bạn đang không sử dụng các cơ sở dữ liệu quan hệ truyền thống để lưu trữ user, bạn sẽ cần phải mở rộng Laravel với authentication user provider của bạn. Chúng ta sẽ dùng phương thức provider trên facade Auth để định nghĩa một custom user provider. Bạn cần đặt lời gọi tới provider trong một service provider

    <?php

    namespace App\Providers;

    use Auth;
    use App\Extensions\RiakUserProvider;
    use Illuminate\Support\ServiceProvider;

    class AuthServiceProvider extends ServiceProvider
    {
        /**
         * Perform post-registration booting of services.
         *
         * @return void
         */
        public function boot()
        {
            Auth::provider('riak', function($app, array $config) {
                // Return an instance of Illuminate\Contracts\Auth\UserProvider...
                return new RiakUserProvider($app['riak.connection']);
            });
        }

        /**
         * Register bindings in the container.
         *
         * @return void
         */
        public function register()
        {
            //
        }
    }

Sau khi bạn đã đăng kí provider với phương thức provider, bạn có thể chuyển sang user provider mới trong file cấu hình config/auth.php. Đầu tiên, định nghĩa một provider mà sử dụng driver mới của bạn:

    'providers' => [
        'users' => [
            'driver' => 'riak',
        ],
    ],

Sau đó bạn có thể sử dụng provider này trong cấu hình guards:

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],

The User Provider Contract

Các implementation Illuminate\Contracts\Auth\UserProvider chỉ chịu trách nhiệm cho việc lấy Illuminate\Contracts\Auth\Authenticatable implementation khỏi một persistent storage system, như là MySQL, Riak, etc. 2 interface này cho phép các cơ chế Laravel authentication tiếp tục hoạt động bất kể dữ liệu user được lưu trữ như thế nào hoặc kiểu của các lớp sử dụng để đại diện nó.

Hãy nhìn qua contract Illuminate\Contracts\Auth\UserProvider:

    <?php

    namespace Illuminate\Contracts\Auth;

    interface UserProvider {

        public function retrieveById($identifier);
        public function retrieveByToken($identifier, $token);
        public function updateRememberToken(Authenticatable $user, $token);
        public function retrieveByCredentials(array $credentials);
        public function validateCredentials(Authenticatable $user, array $credentials);

    }

Hàm retrieveById thông thường nhận một key đại diện cho user, như là một auto-incrementing ID từ MySQL database. Implementation Authenticatable tìm kiếm ID sẽ được lấy và trả về bởi phương thức.

Hàm retrieveByToken truy xuất một user bằng $identifier của họ và $token "remember me", được lưu trong trường remember_token. Giống như với phương thức trước, implementation Authenticatable implementation sẽ được trả về.

Hàm updateRememberToken cập nhật $user trường remember_token với $token mới. Token mới có thể là một token hoàn toàn mới, được gán bởi một đăng nhập "remember me" thành công, hoặc null khi user đăng xuất.

Hàm retrieveByCredentials nhận mảng các credentials truyền vào phương thức Auth:attempt khi xảy ra đăng nhập vào ứng dụng. Phương thức sau đó "query" underlying persistent storage cho việc tìm kiếm các credentials phù hợp. Cơ bạn, phương thức này sẽ chạy 1 truy vấn với điều kiện "where" trên $credentials['username']. Phương thức sau đó trả về một implementation của UserInterface. Phương thức này không nên cố gắng validate hay xác thực mật khẩu.

Phương thức validateCredentials so sánh $user với $credentials để xác thực user. Ví dụ, phương thức này có thể so sánh chuỗi $user->getAuthPassword() tới Hash::make của $credentials['password']. Phương thức này chỉ validate user's credentials và trả về boolean.

The Authenticatable Contract

Bây giờ chúng ta đã khám phá từng phương thức trong UserProvider, hãy xem qua Authenticatable contract. Nhớ rằng, provider nên trả về các implementations của interface này từ phương thức retrieveByIdretrieveByCredentials:

    <?php

    namespace Illuminate\Contracts\Auth;

    interface Authenticatable {

        public function getAuthIdentifierName();
        public function getAuthIdentifier();
        public function getAuthPassword();
        public function getRememberToken();
        public function setRememberToken($value);
        public function getRememberTokenName();

    }
    

Interface này là đơn giản. Phương thức getAuthIdentifierName trả về tên của trường "primary key" của user và getAuthIdentifier trả về "primary key" của user. Trong MySQL back-end sẽ là auto-incrementing primary key. getAuthPassword trả về password đã được hashed. Interface này cho phép hệ thống xác thực làm việc với bất kì lớp User nào, bất kể ORM nào hay các lớp lưu trữ trừu tượng (storage abstraction layer) nào bạn đang sử dụng. Mặc định, Laravel bao gồm một class User trong thư mục app cái mà implement interface này, vì vậy bạn có thể tham khảo class này như một ví dụ.

Events

Laravel xây dựng một loạt events khác nhau trong khi xử lí xác thực. Bạn có thể đính kèm các listener vào những event này trong EventServiceProvider của bạn:

    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        'Illuminate\Auth\Events\Attempting' => [
            'App\Listeners\LogAuthenticationAttempt',
        ],

        'Illuminate\Auth\Events\Login' => [
            'App\Listeners\LogSuccessfulLogin',
        ],

        'Illuminate\Auth\Events\Logout' => [
            'App\Listeners\LogSuccessfulLogout',
        ],

        'Illuminate\Auth\Events\Lockout' => [
            'App\Listeners\LogLockout',
        ],
    ];

Bài viết của mình đến đây là hết hẹn gặp lại các bạn ở các bài viết tiếp theo. 😄

Tài liệu tham khảo:

https://en.wikipedia.org/wiki/Laravel

https://laravel.com/docs/5.8/authentication

Registration Login
Sign in with social account
or
Lost your Password?
Registration Login
Sign in with social account
or
A password will be send on your post
Registration Login
Registration