Luthier CI 認證框架 Authentication Framework

Luthier CI 認證框架 ( Authentication Framework )

內容 Contents

  1. 介紹 Introduction
  2. 建立用戶提供商 Creation of User Providersphp

    1. 用戶實例 User instance
    2. 用戶加載 Users load
    3. 密碼哈希及其驗證 Password hash and its verification
    4. 驗證用戶是否處於活動狀態並已驗證 Validate that a user is active and verified
  3. 與用戶提供商合做 Working with User Providershtml

    1. 用戶登陸 User login
    2. 高級用戶登陸 Advanced user login
  4. 會話 Sessionsweb

    1. 在會話中存儲用戶 Storing a user in the session
    2. 從會話中檢索用戶 Retrieving a user from the session
    3. 自定義會話數據 Custom session data
    4. 刪除當前會話 Deleting the current session
  5. 用戶操做 User Operations算法

    1. 角色驗證 Roles verification
    2. 權限驗證 Permissions verification
  6. 基於控制器的認證 Controller-based authentication數據庫

    1. 通常配置 General configuration
    2. 身份驗證控制器 The authentication controller
    3. 登陸表單 The login form
    4. 登出 Log out
    5. 認證事件 Authentication events

介紹 Introduction

Luthier CI Authentication Framework 是哪一個用戶認證系統是創建在笨的結構。它提供了兩個主要困境的答案:從中獲取用戶以及在應用程序中如何使用這些困境。數組

在此過程當中使用用戶提供程序。用戶提供程序是一個類,負責從某個地方獲取通過身份驗證的用戶,做爲CodeIgniter之間的中介,例如,數據庫,API或甚至加載到內存中的用戶數組。安全

本文針對高級用戶並具備很是特定的身份驗證需求。若是您正在尋找預先配置且易於使用的解決方案,請參閱SimpleAuth的文檔,事實上,這是您將在下面閱讀的全部內容的實現。session

建立用戶提供商 Creation of User Providers

全部用戶提供商都存儲在該application/security/providers文件夾中。此外,您的類必須實現LuthierAuthUserProviderInterface接口,該接口定義如下方法:app

public function getUserClass();

public function loadUserByUsername($username, $password = null);

public function hashPassword($password);

public function verifyPassword($password, $hash);

public function checkUserIsActive(UserInterface $user);

public function checkUserIsVerified(UserInterface $user);

讓咱們首先建立一個名爲的文件MyUserProvider.php,它將成爲咱們的第一個用戶提供者:框架

<?php
# application/security/providers/MyUserProvider.php

use Luthier\Auth\UserProviderInterface;

class MyUserProvider implements UserProviderInterface
{

}

用戶實例 User instance

該用戶實例是經過認證的用戶的邏輯表示:它們包含(和返回)全部的細節,角色和權限。咱們必須在User Provider中實現的第一個方法是getUserClass()返回從如今開始使用的用戶實例的名稱。

咱們將調用咱們的用戶實例MyUser,而後:

<?php
# application/security/providers/MyUserProvider.php

use Luthier\Auth\UserProviderInterface;

class MyUserProvider implements UserProviderInterface
{
    public function getUserClass()
    {
        return 'MyUser';
    }
}

下一步是建立類MyUser。用戶實例文件保存在application/security/providers文件夾中。爲了讓Luthier CI使用它們,類的名稱和文件名必須與getUserClass()方法中返回的名稱相匹配。

用戶實例必須實現LuthierAuthUserInterface接口,該接口定義如下方法:

public function __construct($instance, $roles, $permissions);

public function getEntity();

public function getUsername();

public function getRoles();

public function getPermissions();

實現全部這些方法,咱們的MyUser類看起來像這樣:

<?php
# application/security/providers/MyUser.php

use Luthier\Auth\UserInterface;

class MyUser implements UserInterface
{
    private $user;

    private $roles;

    private $permissions;

    public function __construct($entity, $roles, $permissions)
    {
        $this->user        = $entity;
        $this->roles       = $roles;
        $this->permissions = $permissions;
    }

    public function getEntity()
    {
        return $this->user;
    }

    public function getUsername()
    {
        return $this->user->email;
    }

    public function getRoles()
    {
        return $this->roles;
    }

    public function getPermissions()
    {
        return $this->permissions;
    }
}

咱們的文件結構以下:

application
    |- security
    |   |- providers
    |       | - MyUserProvider.php
    |       | - MyUser.php

用戶加載 Users load

必須從某個地方獲取用戶,而且要實現如下方法,才能實現loadUserByUsername()該功能。

用戶加載只有兩種可能的結果:

  • Successful load: 找到匹配的用戶名和密碼。User Provider返回表示用戶的對象。
  • Failed load: 未找到用戶。如下任何異常拋出:UserNotFoundException,InactiveUserException,UnverifiedUserException或PermissionNotFoundException。

最簡單的示例是在同一個User Provider中聲明一個數組,其中包含可用的用戶:

$users = [
    [
        'name'      => 'John Doe',
        'email'     => 'john@doe.com',
        'password'  => 'foo123',
        'active'    => 1,
        'verified'  => 1,
    ],
    [
        'name'      => 'Alice Brown',
        'email'     => 'alice@brown.com',
        'password'  => 'bar456',
        'active'    => 1,
        'verified'  => 1,
    ]
];

話雖如此,咱們將使用如下代碼更新代碼:

<?php
# application/security/providers/MyUserProvider.php

use Luthier\Auth\UserInterface;
use Luthier\Auth\UserProviderInterface;
use Luthier\Auth\Exception\UserNotFoundException;

class MyUserProvider implements UserProviderInterface
{
    public function getUserClass()
    {
        return 'MyUser';
    }

    public function loadUserByUsername($username, $password = null)
    {
        $users = [
            [
                'name'      => 'John Doe',
                'email'     => 'john@doe.com',
                'password'  => 'foo123',
                'active'    => 1,
                'verified'  => 1,
            ],
            [
                'name'      => 'Alice Brown',
                'email'     => 'alice@brown.com',
                'password'  => 'bar456',
                'active'    => 1,
                'verified'  => 1,
            ]
        ];

        $userEmails   = array_column($users, 'email');
        $foundedIndex = array_search($username, $userEmails);

        if($foundedIndex === false)
        {
            throw new UserNotFoundException('Invalid user credentials!');
        }

        $user = (object) $users[$foundedIndex];

        if($user->password != $password)
        {
            throw new UserNotFoundException('Invalid user credentials!');
        }

        $userClass = $this->getUserClass();

        return new $userClass(
            /*  User data   */ $user,
            /*     Roles    */ ['user'],
            /*  Permissions */ []
        );
    }
}

如今,咱們的用戶提供程序可以搜索數組並在匹配時返回用戶對象,或者若是找不到用戶則拋出UserNotFoundException異常。可是,做爲通常規則,密碼一般不會(也不該該)直接存儲。

相反,存儲使用單向加密算法生成的哈希。考慮這個新用戶數組:

$users = [
    [
        'name'      => 'John Doe',
        'email'     => 'john@doe.com',
        'password'  => '$2y$10$c1iqXvXuFKZ4hI4l.LhCvuacba1fR3OX.uPfPD29j4DkyayC6p4uu',
        'active'    => 1,
        'verified'  => 1,
    ],
    [
        'name'      => 'Alice Brown',
        'email'     => 'alice@brown.com',
        'password'  => '$2y$10$xNHf.J7fbNdph2dy26JAdeQEA70aL/SG9ojrkpR3ocf1qph0Bafay',
        'active'    => 1,
        'verified'  => 1,
    ]
];

每個的密碼仍然徹底相同,不一樣的是如今存儲的是你的哈希而不是純文本的密碼,

因此比較$user-> password == $password 是不夠的。

密碼哈希及其驗證

要實現的如下方法負責在用戶提供程序中生成和驗證密碼哈希:

  • hashPassword(): [string] 以純文本形式接收密碼並返回其哈希值
  • verifyPassword(): [bool] ]以純文本和密碼哈希方式接收密碼,驗證它們是否匹配

邏輯和實現由開發人員自行決定。在咱們的例子中,咱們將使用blowfish算法,留下以下代碼:

<?php
# application/security/providers/MyUserProvider.php

use Luthier\Auth\UserInterface;
use Luthier\Auth\UserProviderInterface;
use Luthier\Auth\Exception\UserNotFoundException;

class MyUserProvider implements UserProviderInterface
{
    public function getUserClass()
    {
        return 'MyUser';
    }

    public function loadUserByUsername($username, $password = null)
    {
        $users = [
            [
                'name'      => 'John Doe',
                'email'     => 'john@doe.com',
                'password'  => '$2y$10$c1iqXvXuFKZ4hI4l.LhCvuacba1fR3OX.uPfPD29j4DkyayC6p4uu',
                'active'    => 1,
                'verified'  => 1,
            ],
            [
                'name'      => 'Alice Brown',
                'email'     => 'alice@brown.com',
                'password'  => '$2y$10$xNHf.J7fbNdph2dy26JAdeQEA70aL/SG9ojrkpR3ocf1qph0Bafay',
                'active'    => 1,
                'verified'  => 1,
            ]
        ];

        $userEmails   = array_column($users, 'email');
        $foundedIndex = array_search($username, $userEmails);

        if($foundedIndex === false)
        {
            throw new UserNotFoundException('Invalid user credentials!');
        }

        $user = (object) $users[$foundedIndex];

        if(!$this->verifyPassword($password, $user->password))
        {
            throw new UserNotFoundException('Invalid user credentials!');
        }

        $userClass = $this->getUserClass();

        return new $userClass(
            /*  User data   */ $user,
            /*     Roles    */ ['user'],
            /*  Permissions */ []
        );
    }

    public function hashPassword($password)
    {
        return password_hash($password, PASSWORD_DEFAULT);
    }

    public function verifyPassword($password, $hash)
    {
        return password_verify($password, $hash);
    }
}

您可能已經注意到$password該loadUserByUsername()方法的參數必須定義爲可選參數。這是由於在每一個請求開始時,Luthier CI會嘗試使用其用戶Provider從新加載最後一個通過身份驗證的用戶,這隻有在能夠從會話中相對安全的數據存儲中獲取用戶時纔有可能,例如ID或用戶名。

所以,咱們必須稍微修改咱們的代碼,以確保即便沒有提供密碼,用戶提供商仍然可以得到用戶:

<?php
# application/security/providers/MyUserProvider.php

use Luthier\Auth\UserInterface;
use Luthier\Auth\UserProviderInterface;
use Luthier\Auth\Exception\UserNotFoundException;

class MyUserProvider implements UserProviderInterface
{
    public function getUserClass()
    {
        return 'MyUser';
    }

    public function loadUserByUsername($username, $password = null)
    {
        $users = [
            [
                'name'      => 'John Doe',
                'email'     => 'john@doe.com',
                'password'  => '$2y$10$c1iqXvXuFKZ4hI4l.LhCvuacba1fR3OX.uPfPD29j4DkyayC6p4uu',
                'active'    => 1,
                'verified'  => 1,
            ],
            [
                'name'      => 'Alice Brown',
                'email'     => 'alice@brown.com',
                'password'  => '$2y$10$xNHf.J7fbNdph2dy26JAdeQEA70aL/SG9ojrkpR3ocf1qph0Bafay',
                'active'    => 1,
                'verified'  => 1,
            ]
        ];

        $userEmails   = array_column($users, 'email');
        $foundedIndex = array_search($username, $userEmails);

        if($foundedIndex === false)
        {
            throw new UserNotFoundException('Invalid user credentials!');
        }

        $user = (object) $users[$foundedIndex];

        if($password !== NULL)
        {
            if(!$this->verifyPassword($password, $user->password))
            {
                throw new UserNotFoundException('Invalid user credentials!');
            }
        }

        $userClass = $this->getUserClass();

        return new $userClass(
            /*  User data   */ $user,
            /*     Roles    */ ['user'],
            /*  Permissions */ []
        );
    }

    public function hashPassword($password)
    {
        return password_hash($password, PASSWORD_DEFAULT);
    }

    public function verifyPassword($password, $hash)
    {
        return password_verify($password, $hash);
    }
}

不要使用md5()或sha1()函數進行密碼哈希

這些算法很是有效,任何人(使用現代計算機和足夠的空閒時間)均可以嘗試經過暴力破解加密。有一節介紹了PHP文檔中的password hashes ,對於那些擔憂安全性這一重要方面的人來講,毫無疑問是必讀的。

驗證用戶是否處於活動狀態並已驗證

這一切仍然是執行方法checkUserIsActive()和checkUserIsVerified(),正如它們的名字,驗證用戶是主動和他們的信息被驗證。

您能夠選擇激活和驗證用戶的條件。在咱們的例子中,對於要激活的用戶,其值active必須等於1,而且要驗證它的值verified必須等於1。

經過實現這兩種方法,咱們的用戶提供程序如今以下所示:

<?php
# application/security/providers/MyUserProvider.php

use Luthier\Auth\UserInterface;
use Luthier\Auth\UserProviderInterface;
use Luthier\Auth\Exception\UserNotFoundException;
use Luthier\Auth\Exception\InactiveUserException;
use Luthier\Auth\Exception\UnverifiedUserException;

class MyUserProvider implements UserProviderInterface
{
    public function getUserClass()
    {
        return 'MyUser';
    }

    public function loadUserByUsername($username, $password = null)
    {
        $users = [
            [
                'name'      => 'John Doe',
                'email'     => 'john@doe.com',
                'password'  => '$2y$10$c1iqXvXuFKZ4hI4l.LhCvuacba1fR3OX.uPfPD29j4DkyayC6p4uu',
                'active'    => 1,
                'verified'  => 1,
            ],
            [
                'name'      => 'Alice Brown',
                'email'     => 'alice@brown.com',
                'password'  => '$2y$10$xNHf.J7fbNdph2dy26JAdeQEA70aL/SG9ojrkpR3ocf1qph0Bafay',
                'active'    => 1,
                'verified'  => 1,
            ]
        ];

        $userEmails   = array_column($users, 'email');
        $foundedIndex = array_search($username, $userEmails);

        if($foundedIndex === false)
        {
            throw new UserNotFoundException('Invalid user credentials!');
        }

        $user = (object) $users[$foundedIndex];

        if($password !== NULL)
        {
            if(!$this->verifyPassword($password, $user->password))
            {
                throw new UserNotFoundException('Invalid user credentials!');
            }
        }

        $userClass = $this->getUserClass();

        return new $userClass(
            /*  User data   */ $user,
            /*     Roles    */ ['user'],
            /*  Permissions */ []
        );
    }

    public function hashPassword($password)
    {
        return password_hash($password, PASSWORD_DEFAULT);
    }

    public function verifyPassword($password, $hash)
    {
        return password_verify($password, $hash);
    }

    final public function checkUserIsActive(UserInterface $user)
    {
        /*
         * The getEntity() method is used to return an array / object / entity with the
         * user data. In our case, it is an object, so we can use
         * the following chained syntax:
         */
        if($user->getEntity()->active == 0)
        {
            throw new InactiveUserException();
        }
    }


    final public function checkUserIsVerified(UserInterface $user)
    {
        /*
         * The same here:
         */
        if($user->getEntity()->verified == 0)
        {
            throw new UnverifiedUserException();
        }
    }
}

完成!您已經建立了第一個用戶提供程序和附加的用戶實例。您已準備好對用戶進行身份驗證。

與用戶提供商合做

在使用用戶提供程序以前,您應該作的第一件事是將其上傳到您的應用程序。爲此,請使用類的靜態loadUserProvider()方法Auth。

例如,要加載之前的User Provider,語法以下:

$myUserProvider = Auth::loadUserProvider('MyUserProvider');

用戶登陸

要執行登陸,請使用loadUserByUsername()User Provider 的方法,其中第一個參數是用戶名/電子郵件,第二個參數是您的密碼:

// We load a User Provider:
$myUserProvider = Auth::loadUserProvider('MyUserProvider');

// Returns the user object corresponding to 'john@doe.com':
$john = $myUserProvider->loadUserByUsername('john@doe.com', 'foo123');

// Returns the corresponding user object to 'alice@brown.com':
$alice = $myUserProvider->loadUserByUsername('alice@brown.com', 'bar456');

用戶提供程序的設計使得只能使用用戶名/電子郵件登陸:

$alice = $myUserProvider->loadUserByUsername('alice@brown.com');

登陸期間的任何錯誤都會產生異常,應根據具體狀況捕獲並處理:

// ERROR: The password of john@doe.com is incorrect!
// (An exception 'UserNotFoundException' will be thrown)
$jhon = $myUserProvider->loadUserByUsername('john@doe.com', 'wrong123');

// ERROR: The user anderson@example.com doesn't exist!
// (An exception 'UserNotFoundException' will be thrown)
$anderson = $myUserProvider->loadUserByUsername('anderson@example.com', 'test123');

高級用戶登陸

該用戶提供返回用戶,但這並不意味着他們真的有權登陸。checkUserIsActive()和checkUserIsVerified()方法添加方便額外的檢查。

考慮如下用戶數組:

$users = [
    [
        'name'      => 'Alex Rodriguez',
        'email'     => 'alex@rodriguez.com',
        'password'  => '$2y$10$2nXHy1LyNL217hfyINGKy.Ef5uhxa1FdmlMDw.nbGOkSEJtT6IJWy',
        'active'    => 0,
        'verified'  => 1,
    ],
    [
        'name'      => 'Alice Brown',
        'email'     => 'alice@brown.com',
        'password'  => '$2y$10$xNHf.J7fbNdph2dy26JAdeQEA70aL/SG9ojrkpR3ocf1qph0Bafay',
        'active'    => 1,
        'verified'  => 0,
    ],
    [
        'name'      => 'Jessica Hudson',
        'email'     => 'jessica@example.com',
        'password'  => '$2y$10$IpNrG1VG53DrborE4Tl6LevtVgVfoO9.Ef9TBVgH9I10DLRnML9gi',
        'active'    => 1,
        'verified'  => 1,
    ],
];

如下登陸代碼:

use Luthier\Auth\Exception\UserNotFoundException;
use Luthier\Auth\Exception\InactiveUserException;
use Luthier\Auth\Exception\UnverifiedUserException;

function advanced_login($username)
{
    $myUserProvider = Auth::loadUserProvider('MyUserProvider');

    try
    {
        $user = $myUserProvider->loadUserByUsername($username);
                $myUserProvider->checkUserIsActive($user);
                $myUserProvider->checkUserIsVerified($user);
    }
    catch(UserNotFoundException $e)
    {
        return 'ERROR: User not found!';
    }
    catch(InactiveUserException $e)
    {
        return 'ERROR: Inactive user!';
    }
    catch(UnverifiedUserException $e)
    {
        return 'ERROR: Unverified user!';
    }

    return 'OK: Login success!';
}

var_dump( advanced_login('alex@rodriguez.com') );  // ERROR: Inactive user!
var_dump( advanced_login('alice@brown.com') );     // ERROR: Unverified user!
var_dump( advanced_login('jack@grimes.com') );     // ERROR: User not found!
var_dump( advanced_login('jessica@example.com') ); // OK: Login success!

雖然alex@rodriguez.com而且alice@brown.com存在於用戶陣列內,可是根據用戶提供者,第一個是非活動的而第二個未被驗證,而且因爲用戶jack@grimes .com不存在,惟一能夠登陸的用戶是jessica@example.com。

因此,你沒必要定義advanced_login在應用程序中一次又一次的功能,已經有兩個方法,作一樣的事情:Auth::attempt()和Auth::bypass(),第一個用於經過用戶名和密碼,第二經過用戶名登陸登陸只。

除了處理異常外,如下表達式與前面的代碼等效:

Auth::bypass('alex@rodriguez.com', 'MyUserProvider');
Auth::bypass('alice@brown.com', 'MyUserProvider');

Auth::attempt('alex@rodriguez.com', 'foo123', 'MyUserProvider');
Auth::attempt('alice@brown.com', 'bar456', 'MyUserProvider');

會話 Sessions

若是通過身份驗證的用戶不能繼續瀏覽,那麼可以登陸的用途是什麼?所述Auth類包括用於存儲和會話中得到的用戶的功能。

在會話中存儲用戶 Storing a user in the session

要在會話中存儲用戶,請使用靜態方法store():

$alice = $myUserProvider->loadUserByUsername('alice@brown.com');
Auth::store($alice);

只要您不刪除會話或它過時,這將在導航的其他部分保存通過身份驗證的用戶。

從會話中檢索用戶

要獲取存儲在會話中的用戶,請使用靜態方法user():

$alice = Auth::user();

此方法返回用戶實例的對象,或者NULL若是沒有用戶存儲。

例:

$alice = Auth::user();

// The user entity
// (The returned value depends on the User Provider, although the most common is that it is an object)
$alice->getEntity();

// An array with the roles that the User Provider has assigned to the user
$alice->getRoles();

// An array with the permissions that the User Provider has assigned to the user
$alice->getPermissions();

您可使用靜態方法檢查用戶是匿名的(或邀請的)isGuest():

if( Auth::isGuest() )
{
    echo "Hi Guest!";
}
else
{
    echo "Welcome " . Auth::user()->getEntity()->name . "!";
}

自定義會話數據 Custom session data

要在一個位置獲取並存儲您本身的會話數據(與身份驗證相關),請使用靜態方法session(),其第一個參數是要存儲的值的名稱,第二個參數是指定的值。

例:

// Store a value
Auth::session('my_value', 'foo');

// Get a value
$myValue = Auth::session('my_value');
var_dump( $myValue ); // foo

// Get ALL stored values
var_dump( Auth::session() ); // [ 'my_value' => 'foo' ]

刪除當前會話 Deleting the current session

要從當前身份驗證會話中刪除全部數據(包括當前存儲的通過身份驗證的用戶),請使用靜態方法destroy:

Auth::destroy();

用戶操做 Users operations

有兩種操做可用於對通過身份驗證的用戶執行:角色驗證和權限驗證。

角色驗證 Roles verification

要驗證用戶是否具備某個角色,請使用static方法isRole(),其第一個參數是要驗證的角色的名稱:

Auth::isRole('user');

You can supply a different user object to the one stored in session as a second argument:

$alice = Auth::loadUserProvider('MyUserProvider')->bypass('alice@brown.com');
Auth::isRole('admin', $user);

權限驗證 Permissions verification

要驗證用戶是否具備特定權限,請使用static方法isGranted(),其第一個參數是要驗證的權限的名稱:

Auth::isGranted('general.read');

您能夠將另外一個用戶對象提供給存儲在會話中的用戶對象做爲第二個參數:

$alice = Auth::loadUserProvider('MyUserProvider')->bypass('alice@brown.com');
Auth::isGranted('general.read', $user);

基於控制器的認證 Controller-based authentication

到目前爲止,您已經看到Luthier CI身份驗證框架的元素單獨工做。好消息是你可讓它們一塊兒工做!這一切都歸功於咱們稱之爲基於控制器的身份驗證的方法。

基於控制器的身份驗證包括兩個接口的實現,一個在控制器中,另外一個在中間件中,您能夠選擇自動化用戶身份驗證過程。

通常配置 General configuration

您能夠建立(儘管不是必需的)在應用程序文件夾auth.php內調用的config文件,以配置基於驅動程序的身份驗證的選項。SimpleAuth文檔中解釋了每一個選項的含義

這是配置文件的示例:

<?php
# application/config/auth.php

$config['auth_login_route']  = 'login';

$config['auth_logout_route'] = 'logout';

$config['auth_login_route_redirect'] = 'dashboard';

$config['auth_logout_route_redirect'] = 'homepage';

$config['auth_route_auto_redirect'] = [];

$config['auth_form_username_field'] = 'email';

$config['auth_form_password_field'] = 'password';

$config['auth_session_var'] = 'auth';

若是該文件不存在,將使用默認配置,如上所述。

身份驗證控制器 The authentication controller

身份驗證驅動程序是實現該Luthier\Auth\ControllerInterface接口的任何CodeIgniter控制器,它定義瞭如下方法:

public function getUserProvider();

public function getMiddleware();

public function login();

public function logout();

public function signup();

public function emailVerification($token);

public function passwordReset();

public function passwordResetForm($token);

讓咱們首先建立一個名爲的控制器 AuthController.php, 它實現了全部必需的方法:

<?php
# application/controllers/AuthController.php

defined('BASEPATH') OR exit('No direct script access allowed');

use Luthier\Auth\ControllerInterface;

class AuthController extends CI_Controller implements ControllerInterface
{
    public function getUserProvider()
    {
        return 'MyUserProvider';
    }

    public function getMiddleware()
    {
        return 'MyAuthMiddleware';
    }

    public function login()
    {
        $this->load->view('auth/login.php');
    }

    public function logout()
    {
        return;
    }

    public function signup()
    {
        $this->load->view('auth/signup.php');
    }

    public function emailVerification($token)
    {
        $this->load->view('auth/email_verification.php');
    }

    public function passwordReset()
    {
        $this->load->view('auth/password_reset.php');
    }

    public function passwordResetForm($token)
    {
        $this->load->view('auth/password_reset_form.php');
    }
}

getUserProvider()和getMiddleware()方法返回的值對應於用戶提供程序和中間件,其中包含將在後續過程當中使用的身份驗證事件。對於User Provider,它將與前面的示例相同,MyUserProvider:

public function getUserProvider()
{
    return 'MyUserProvider';
}

對於具備身份驗證事件的中間件,將使用一個調用MyAuthMiddleware(尚不存在),咱們將在稍後討論:

public function `getMiddleware()
{
    return 'MyAuthMiddleware';
}

該login()和logout()方法定義會話的開始和結束。當用戶登陸時,Luthier CI會自動截獲並處理請求,所以在咱們的控制器中,咱們只須要使用登陸表單顯示一個視圖:

public function login()
{
    $this->load->view('auth/login.php');
}

註銷也將由Luthier CI處理,所以咱們的logout()方法在控制器級別絕對沒有任何做用:

public function logout()
{
    return;
}

其他方法的實現取決於您,但咱們會讓您瞭解它們的功能應該是什麼:

  • signup(): 具備用戶註冊表的全部邏輯的方法。在這裏,您必須顯示註冊表單並對其進行處理(將用戶保存在數據庫中等)
  • emailVerification( string $token ): 負責驗證新註冊用戶的電子郵件。一般,您已收到一封電子郵件,其中包含帶有驗證令牌($token)的連接。
  • passwordReset(): 顯示密碼重置的表單。
  • passwordResetForm( string $token ): 檢查密碼重置請求。幾乎老是它是一封發送給用戶的電子郵件,其中包含一個帶有密碼重置令牌的連接($token)

登陸表單 The login form

咱們的login()方法是指一個叫作的視圖auth/login.php。讓咱們建立它:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Log in</title>
</head>
<body>
    <h1>Log in</h1>
    <form method="post">
        <input type="text" name="username" required />
        <input type="password" name="oasswird" required />
        <button type="submit">Log in</button>
    </form>
</body>
</html>

而後,咱們必須在咱們的web.php文件中添加如下路徑:

Route::match(['get', 'post'], 'login', 'AuthController@login')->name('login');

訪問url時/login,必須顯示咱們建立的登陸表單:

<p align="center">

<img src="img/luthier-ci-login-screen.png" alt="Login screen" class="img-responsive" />

</p>

您能夠得到具備在身份驗證過程當中發生的錯誤的安排,並在您的視圖中使用它來通知用戶。使用該Auth::messages()方法,以下所示:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Log in</title>
</head>
<body>
    <h1>Log in</h1>
    <?php

        // We will help ourselves with an array with the translations of the returned
        // error codes (they are always the same)

        $errorMessages = [
            'ERR_LOGIN_INVALID_CREDENTIALS' => 'Incorrect email or password',
            'ERR_LOGIN_INACTIVE_USER'       => 'Inactive user',
            'ERR_LOGIN_UNVERIFIED_USER'     => 'Unverified user',
        ];
    ?>

    <?php foreach(Auth::messages() as $type => $message){ ?>
        <div class="alert alert-<?= $type ;?>">
            <?= $errorMessages[$message] ;?>
        </div>
    <?php } ?>

    <form method="post">
        <input type="email" name="email" required />
        <input type="password" name="password" required />
        <button type="submit">Log in</button>
    </form>
</body>
</html>

您的登陸表已準備就緒!

您能夠隨意嘗試用戶提供商中提供的任意用戶名/密碼組合。登陸時,您將被重定向到您在選項中定義的路徑$config ['auth_login_route_redirect'],或者若是沒有這樣的路徑,則重定向到應用程序的根URL。

註銷 Log out

如今咱們將配置註銷。惟一須要的是定義將要使用的路由,默認狀況下它將是您調用的路由logout:

Route::get('logout', 'AuthController@logout')->name('logout');

咱們的路線文件最終將相似於:

Route::match(['get', 'post'], 'login', 'AuthController@login')->name('login');
Route::get('logout', 'AuthController@logout')->name('logout');

認證事件 Authentication events

你還記得getMiddleware()控制器的方法嗎?返回特殊中間件的名稱:具備身份驗證事件的中間件。

咱們將建立一個名爲MyAuthMiddleware擴展抽象類的中間件LuthierAuthMiddleware,經過實現全部必需的方法,它將以下所示:

<?php
# application/middleware/MyAuthMiddleware.php

defined('BASEPATH') OR exit('No direct script access allowed');

use Luthier\Route;
use Luthier\Auth\UserInterface;

class MyAuthMiddleware extends Luthier\Auth\Middleware
{
    public function preLogin(Route $route)
    {
        return;
    }

    public function onLoginSuccess(UserInterface $user)
    {
        return;
    }

    public function onLoginFailed($username)
    {
        return;
    }

    public function onLoginInactiveUser(UserInterface $user)
    {
        return;
    }

    public function onLoginUnverifiedUser(UserInterface $user)
    {
        return;
    }

    public function onLogout()
    {
        return;
    }
}

每種方法都對應一個身份驗證事件,以下所述:

  • preLogin: 用戶訪問登陸路徑時觸發的事件,不管是否登陸。
  • onLoginSuccess: 在成功登陸會話以後以及隨後的重定向以前當即觸發事件。
  • onLoginFailed: 在會話嘗試失敗後,以及隨後的重定向以前觸發的事件。
  • onLoginInactiveUser: 若是InactiveUserException在用戶提供程序中引起異常,則觸發事件,對應於非活動用戶登陸錯誤。
  • onLoginUnverifiedUser: 若是UnverifiedUserException在User Provider內拋出異常,則觸發事件,對應於未驗證用戶登陸時的錯誤。
  • onLogout: 用戶關閉會話後當即觸發事件。
相關文章
相關標籤/搜索