Laravel 5.3 自帶多許可權登入正確姿勢

storefee發表於2017-07-29

前言

  • 因為在網上沒有看到一篇完整的講述5.3多許可權登入驗證的問題,而且以前我們是需要通過外掛包來實現,現在5.3中可以直接用內部機制。所以拋磚引玉的講一天的研究成果成文分享給大家。希望大家快樂學習,也同樣樂於分享。

在正式開始之前,請確認已經熟悉對應的laravel-china翻譯的官方文件:http://learnku.com/docs/laravel/5.3/authen...

1,建立模型

namespace App\Models;

use App\Models\Traits\AdminTrait;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class Admin  extends Authenticatable
{
    use Notifiable;
    use AdminTrait;

    protected $table = "admins";
……
}

這裡注意是extends Authenticatable,而非預設的model

修改config/auth.php

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

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
    ],

        'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Models\Admin::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],
  • 在guard陣列裡面規定了3套驗證機制,分別是會話型的user 和 admin,這兩種是需要我們進行登入驗證的(一般採用中介軟體方式),另外一種就是前後端分離時會用到的api,這種一般都是通過指定過期的token進行臨時性的會話,這也是為了後面控制器中使用guard做準備。同時注意providers中驅動模型採用eloquent方式,也就是資料模型驅動。

2,接下來建立控制器

<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Auth;
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 = '/admin/dashboard';

    /**
     * 如果是在位址列中輸入登入url,就需要先判斷是否已經登入。
     *
     */
    public function getLogin()
    {
        if ($this->guard()->check()) {
            return redirect()->route('admin.dashboard.index');
        }
        return view('admin.auth.login');
    }

    /**
     * 採用post方法進行登入時採用的驗證機制
     *
     */
    public function postLogin(Request $request)
    {
        $this->validate($request, [
            $this->loginUsername() => 'required', 'password' => 'required',
        ]);
        //  $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 ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

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

        /////////////////////////////////////////////////////////////////
        //         注意下面採用的是Auth::guard('admin’)驗證方式。          //
        ////////////////////////////////////////////////////////////////

        // if ($this->attemptLogin($request)) {
        if (Auth::guard('admin')  //也可以寫成:$this->guard(),這樣更利於程式碼的維護,原因自行分析。
            ->attempt(['email'=>$request->email, 'password'=>$request->password],
            $request->has('remember'))) {
        //if (Auth::attempt(['email'=>$request->email,'password'=>$request->password], $request->has('remember')))            {

               return redirect()->route('admin.dashboard.index');
        }

        // 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);
    }

    /**
     * 可選擇不同的欄位作為校驗和登入名用。
     * 比如,你登入是採用使用者名稱登入,這裡就return 'name‘,如果你是想用email進行登入,就在這裡返回email字串
     * 是不是非常方便?
     */
    public function loginUsername()
    {
        return 'email';
    }

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

    /**
     * 退出登入,同時跳轉到登入頁面。
     *
     */
    public function getLogout(Request $request)
    {
        $this->guard()->logout();

        return redirect()->route('admin.login');
    }
}
  • 5.1中是沒有采用guard的,所以這裡需要大家先看官方文件,再來看本文的原因所在。
  • 被註釋的驗證程式碼是5.1中的驗證方式,大家可以對比看看有哪些不同。

3,路由

3.1 配置Kernel.php

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],

    'admin' => [
        \App\Http\Middleware\AdminAuthenticate::class,
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
protected $routeMiddleware = [
    'admin'       => \App\Http\Middleware\AdminAuthenticate::class,
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
  • 這裡面的middlewareGroups裡的admin中也必須加上各種必須中介軟體,不然在routes/admin.php中雖然加上了“admin”中介軟體,還是無法進入對應的方法中進行驗證。其他元件也必須加上,不然cookies,sessions,CSRF 的功能就沒有了。其中,
  • web 一般是我們用於前端的各種操作進行處理;
  • api 是進行無狀態回話介面設計,方便前後端分離,或者其他站點授權訪問機制;
  • admin 主要是用於後臺管理方面;

上面AdminAuthenticate.php具體內容:

<?php

namespace App\Http\Middleware;

use Auth;
use Closure;

class AdminAuthenticate
{
    public function handle($request, Closure $next)
    {
        if (!Auth::guard('admin')->check()) {
            return redirect()->route('admin.login');
        }

        return $next($request);
    }
}

3.2 配置RouteServiceProvider.php

  • 這裡配置的目的是將不同用途的路由拆分到不同的檔案中,同時採取不同的驗證機制,便於合理組織我們的程式碼。
public function map()
{
    $this->mapApiRoutes();
    $this->mapWebRoutes();
    $this->mapAdminRoutes();
}

protected function mapWebRoutes()
{
    Route::group([
        'middleware' => 'web',
        'namespace'  => $this->namespace,
    ], function ($router) {
        require base_path('routes/web.php');
    });
}

protected function mapApiRoutes()
{
    Route::group([
        'middleware' => 'api',
        'namespace'  => $this->namespace,
        'prefix'     => 'api',
    ], function ($router) {
        require base_path('routes/api.php');
    });
}

protected function mapAdminRoutes()
{
    Route::group([
        'namespace'  => 'App\Http\Controllers\Admin',
        'prefix'     => 'admin',
        'middleware' => 'web',
    ], function ($router) {
        require base_path('routes/admin.php');
    });
}

這裡面特別要強調mapAdminRoutes方法,這裡面的middleware千萬不要寫成admin了,不然會形成無限死迴圈的。始終會進入AdminAuthenticate.php中的驗證方法出不去。

3.3 配置routes/admin.php

Route::get('login', 'LoginController@getLogin')->name('admin.login');
Route::post('login', 'LoginController@postLogin')->name('admin.post.login');
Route::get('logout', 'LoginController@getLogout')->name('admin.logout');

Route::group(['middleware' => 'admin', 'as' => 'admin.'], function () {
    Route::get('/', 'HomeController@index');
    Route::get('/dashboard', 'DashboardController@index')->name('dashboard.index');

}

重要的事情再次強調下:

  • 上面Kernel中的middlewareGroups【admin】中也必須加上\App\Http\Middleware\AdminAuthenticate::class,,不然在routes/admin.php中雖然加上了“admin”中介軟體,還是無法進入對應的方法中進行驗證。

2017.7.30
[TODO]
忘了寫config下面的auth配置,晚上補上。
[DONE] 2017.7.30 10時補充完整。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

努力是不會騙人的!

相關文章