Authentication

Giới thiệu

Bạn có muốn bắt đầu nhanh không? Chỉ cần chạy php artisan make:authphp artisan migrate trong một project mới. Khi đó, vào trình duyệt gõ địa chỉ http://your-app.dev/register hoặc bất kỳ URL được gán cho ứng dụng. Đó là hai lệnh để sử dụng scaffolding cho việc xác thực tài khoản ứng dụng của bạn!

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 chỉ việc dùng. 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 tùy biến cách xử lí của các dịch vụ authentication.

Tại phần core của nó, các cơ sở authentication của Laravel được tạo bởi "guards" và "providers". Guards định nghĩa cái cách mà các user được authentication 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.

Providers định nghĩa cách mà user được truy xuất từ 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. Tuy nhiên, bạn có thể thoải mái thêm provider nếu cần vào ứng dụng của bạn.

Đùng lo lắng nếu tất các điều này nghe có vẻ bối rối. Hầu hết các ứng dụng sẽ không cần tùy biến các cấu hình authentication mặc định.

Những chú ý về database

Mặc định, Laravel thêm một App\User Eloquent model trong thư mục app. Model này có thể sử dụng với Eloquent authentication driver mặc định. Nếu ứng dụng của bạn không sử dụng Eloquent, bạn có thể dùng database authentication driver sử dụng Laravel query builder.

Khi xây dựng database schema cho model App\User model, đả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ự sẽ là một lựa chọn tốt.

Ngoài ra, Bạn cũng nên xác nhận table users (or equivalent) table chứa một nullable, cột remember_token chứa 100 characters. 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.

Bắt đầu nhanh với authentication

Laravel có một số pre-built authentication controllers, chúng ở trong thư mục App\Http\Controllers\Auth namespace. Controller RegisterController xử lý đăng ký user mới, Controller LoginController xử lý authentication, controller ForgotPasswordController xử lý gửi link để khôi phục lại mật khẩu, and controller ResetPasswordController chứa logic khôi phục mật khẩu. Mỗi controllers sử dụng trait cần thiết cho mỗi phương thức. Đối với nhiều ứng dụng, bạn sẽ không cần phải chỉnh sửa nó.

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 lệnh

php artisan make:auth

Lệnh 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 authentication. Controller HomeController sẽ tự động được sinh ra để xử lý request post-login cho trang dashboard của ứng dụng.

Views

Như đã đề cập ở phần trên, lệnh 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.

Lệnh 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. Tất cả những view này sử dụng framework Bootstrap, nhưng bạn thoải mái tùy biến 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.

Tùy chỉnh đường dẫn

Khi một user được xác nhận thành công, họ sẽ được chuyển sang URI /home. 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, và ResetPasswordController:

protected $redirectTo = '/';

Khi một user không được xác nhận thành công, họ sẽ tự động chuyển hướng quay lại form đăng nhập.

Tùy chỉnh guard

Bạn cũng có thể tùy biến "guard" cái mà sử dụng để authentication user. Để bắt đầu, định nghĩa một phương thức guard trong LoginController, RegisterController, và ResetPasswordController. Hàm này sẽ trả về một thể hiện guard:

use Illuminate\Support\Facades\Auth;

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

Tùy biến Validation / Storage

Để 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 chứa những quy định validation cho việc đăng ký một user mới. Bạn có thể thoải mái tùy biến theo ý bạn.

Phương thức create của RegisterController có chịu trách nhiệm tạo mới một bản ghi mới App\User Eloquent ORM. Bạn có thể tự do tùy biến nếu cần theo ý bạn.

Nhận người dùng đã authenticate

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

use Illuminate\Support\Facades\Auth;

$user = Auth::user();

Ngoài ra, mội khi user đã được authenticate, bạn có thể truy cập thông qua môt instance Illuminate\Http\Request. Nhớ rằng, type-hinted class sẽ tự động được injecte vào trong phương thức của controller:

<?php

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...
    }
}

Xác thực user nếu tồn tại

Để 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 trong Auth facade, nó sẽ trả về true nếu user được authenticate:

use Illuminate\Support\Facades\Auth;

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

Mặc dùng có thể xác định user đã được xác thực bằng phương thức check, bạn có th sử dụng một middleware để xác thực user được authenticate trước khi cho phép user đó truy cập vào routes / controllers. Để tìm hiểu thêm, xem tại bảo vệ routes.

Bảo vệ Routes

Route middleware ccó 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 Illuminate\Auth\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');

Tất nhiên, bạn có thể sử dụng controllers, bạn có thể gọi phương thức middleware từ hàm constructor của controller thay vì gán nó trực tiếp vào route:

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

Chỉ định một guard

Khi bạn gán auth middleware vào route, bạn cũng có thể chỉ định guard nào sẽ được dùng để thực thi việc authentication.Guard được chỉ định nên tương ứng với một trong các key trong mảng guards của file cấu hình auth.php:

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

Login Throttling

Nếu bạn sử dụng class LoginController của Laravel, Illuminate\Foundation\Auth\ThrottlesLogins trait sẽ được thêm vào controller. 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 throttling này là duy nhất với một username / e-mail và địa chỉ IP của họ.

Authenticating người dùng thủ công

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 authentication services của Laravel thông qua Auth facade, vì vậy chúng ta cần đảm bảo import facade Auth facade ở đầu class. Tiếp thep, hãy kiểm tra phương thức attempt:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
    /**
     * Handle an authentication attempt.
     *
     * @return  Response
     */
    public function authenticate()
    {
        if (Auth::attempt(['email' => $email, 'password' => $password])) {
            // 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 password trùng hợp, một session sẽ được bắt đầu cho user.

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

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ó.

Thêm điều kiện được chỉ định

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.
}

Trong ví vụ này, email là không bắt buộc, nó chỉ được sử dụng như là một ví dụ. Bạn nên sử dụng những tên cột khác tương ứng với "username" trong database.

Truy cập thể hiện guard chỉ định

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 trong Auth facade. Đ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 mnê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)) {
    //
}

Đăng xuât

Để đă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 trong Auth facade. Việc này sẽ xóa toàn bộ thông tin xác thực trong session của user:

Auth::logout();

Ghi nhớ người dùng

Nếu bạn muốn cung cấp chức năng "remember me" ftrong ứ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 authentication vô thời hạn, hoặc tới khi họ đăng xuất thủ công. Tất nhiện, bảng users phải có một cột tring remember_token, cái mà sẽ được dùng để lưu "remember me" token.

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

Nếu bạn sử dụng controller LoginController cung cấp bởi Laravel, tính năng "remember" đã được tích hợp bởi traits sử dụng trong controller.

Nếu bạn đang "remembering" người dùng, bạn có thể sử dụng phương thức viaRemember để xác định nếu người dung đã authentication sử dụng cookie "remember me":

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

Các phương thức Authentication khác

Authenticate một thể hiện người dùng

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. Đối tượng đã cho phải là một imlementation của Illuminate\Contracts\Auth\Authenticatable contract. Tất nhiện, model App\User model 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 thể hiện guard bạn muốn sử dụng:

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

Authenticate người dùng bởi 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 để authentication:

Auth::loginUsingId(1);

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

Authenticate người dùng một lần

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:

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". Để bắt đầu, đính kèm auth.basic middleware vào route. Middleware auth.basic được bao gồm trong Laravel framework, vì thế bạn không cần định nghĩa nó:

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

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ẽ sử dụng cột email ctrên các bản ghi như "username".

Một lưu ý về 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:

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. Để làm nó, Định nghĩa một middleware cái nà 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 Illuminate\Support\Facades\Auth;

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

}

Tiếp thep, Đăng ký route middleware và gán nó vào một route:

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

Thêm tùy biến guard

bạn có thể định nghĩa thêm authentication guard bằng cách sử dụng phương thức extend trong Auth facade. Bạn nên đặt nó gọi provider ở trong service provider. Laravel đã có sẵn AuthServiceProvider, chúng ta có thể code nó ở trong provider này:

<?php

namespace App\Providers;

use App\Services\Auth\JwtGuard;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * Register any application authentication / authorization services.
     *
     * @return  void
     */
    public function boot()
    {
        $this->registerPolicies();

        Auth::extend('jwt', function ($app, $name, array $config) {
            // Return an instance of Illuminate\Contracts\Auth\Guard...

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

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, bạn có thể sử dụng guard trong file guards của file cấu hình auth.php:

'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 trong Auth facade để định nghĩa một custom user provider:

<?php

namespace App\Providers;

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

class AuthServiceProvider extends ServiceProvider
{
    /**
     * Register any application authentication / authorization services.
     *
     * @return  void
     */
    public function boot()
    {
        $this->registerPolicies();

        Auth::provider('riak', function ($app, array $config) {
            // Return an instance of Illuminate\Contracts\Auth\UserProvider...

            return new RiakUserProvider($app->make('riak.connection'));
        });
    }
}

Sau khi bạn đã đăng kí provider với phương thức providerbạn có thể chuyển sang user provider mới trong file cấu hình 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. Hai 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 Illuminate\Contracts\Auth\UserProvider contract:

<?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 và "remember me" $token, được lưu ở trong trường remember_token. Giống như với phương thức trước, implementation Authenticatable sẽ được trả về.

Hàm updateRememberToken cập nhật trường $user 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 người dùng đă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 Authenticatable. Phương thức này không nên cố gắng validate hay authentiaction mật khẩu..

Hàm validateCredentials so sánh $user với $credentials để authenticate người dùng. Ví dụ, phương thức này có thể so sánh chuỗi Hash::check với giá trị của $user->getAuthPassword() to the value of $credentials['password']. Phương thức này chỉ trả về true hoặc false nếu mật khẩu không đúng.

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 đơn giản. Hàm getAuthIdentifierName mtrả về tên của trường "primary key" của người dùng và getAuthIdentifier trả về "primary key" của người dùng. Trong MySQL back-end sẽ là auto-incrementing primary key. Hàm 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 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:

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

    'Illuminate\Auth\Events\Attempting' => [
        'App\Listeners\LogAuthenticationAttempt',
    ],

    'Illuminate\Auth\Events\Authenticated' => [
        'App\Listeners\LogAuthenticated',
    ],

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

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

    'Illuminate\Auth\Events\Lockout' => [
        'App\Listeners\LogLockout',
    ],
];
Nguồn: https://laravel.com/docs/5.3/authenticate