Laravel學習筆記六-權限管理與中間件Middleware

這一節咱們將給相關的動做頁面添加權限,如已經登陸的用戶將不會看到註冊、登陸按鈕,更不會對別人的我的資料進行編輯操做,除非是管理員,這裏咱們將藉助Laravel提供的中間件Middleware快速實現。php

1、HTTP 中間件

HTTP 中間件提供了一個方便的機制來過濾進入應用程序的 HTTP 請求,例如,Laravel 自己使用中間件來驗證用戶的身份,若是用戶未經過身份驗證,中間件將會把用戶導向登陸頁面,反之,當用戶經過了身份驗證,中間件將會經過此請求並接着往下執行。html

固然,除了身份驗證以外,中間件也能夠被用來運行各式各樣的任務,CORS 中間件負責替全部即將離開程序的響應加入適當的標頭。而日誌中間件則能夠記錄全部傳入應用程序的請求。laravel

Laravel 框架已經內置了一些中間件,包括維護、身份驗證、CSRF 保護,等等。全部的中間件都放在app/Http/Middleware 目錄內。ajax

如果但願每一個 HTTP 請求都通過一箇中間件,只要將中間件的類加入到 app/Http/Kernel.php 的 $middleware 屬性清單列表中。session

// 在 App\Http\Kernel 類內...
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,];

Laravel 提供的 Auth 中間件在過濾指定動做時,若是該用戶未經過身份驗證,默認將會被重定向到 auth/login 登陸頁面,但咱們在應用中使用的登陸頁面地址是 /login,所以咱們須要對 Auth 中間件默認的重定向地址進行更改。app

app/Http/Middleware/Authenticate.php框架

<?php

namespace App\Http\Middleware;
// 
// 

class Authenticate
{
  // 
  // 
    public function handle($request, Closure $next)
    {
        if ($this->auth->guest()) {
            if ($request->ajax()) {
                return response('Unauthorized.', 401);
            } else {
                return redirect()->guest('login');
            }
        }

        return $next($request);
    }
}

經過閱讀 Auth 中間件的源碼可知,Auth 中間件會先判斷當前用戶是否爲遊客(未登陸狀態的用戶),當用戶爲遊客且請求方式是 ajax 時,則拋出一個 401 響應信息,若是不是經過 ajax 的方式請求,則重定向到登陸頁面。最後,若是用戶爲已登陸狀態,則接着執行下一個請求。ide

如今退出登陸,再次嘗試訪問 http://sample.app/users/1/edit 頁面將會被重定向到登陸頁面。ui

2、受權策略 (Policy)

在完成對用戶未登陸限制以後,咱們來研究下已登陸用戶的權限驗證,即只有用戶本身才能編輯本身的我的信息,其餘用戶無權編輯。
在 Laravel 中可使用 受權策略(Policy) 來對用戶的操做權限進行驗證,在用戶未經受權進行操做時將返回 403 異常。this

咱們可使用如下命令來生成一個名爲 UserPolicy 的受權策略類文件,用於管理用戶模型的受權。

$ php artisan make:policy UserPolicy

什麼是受權策略呢?咱們通常在我的資料編輯時,須要驗證是否爲用戶本身,這樣纔有權限修改,先查出用戶的我的信息,而後再和登陸的用戶ID判斷是否爲同一我的,而Laravel爲咱們提供了一套受權機制,只需新建一個受權策略,而後將其直接調用:

$ php artisan make:policy UserPolicy

<?php

namespace App\Policies;

use Illuminate\Auth\Access\HandlesAuthorization;
use App\Models\User;

class UserPolicy
{
    use HandlesAuthorization;

    public function update(User $currentUser, User $user)
    {
        return $currentUser->id === $user->id;
    }
}

update 方法接收兩個參數,第一個參數默認爲當前登陸用戶實例,第二個參數則爲要進行受權的用戶實例。當兩個 id 相同時,則表明兩個用戶是相同用戶,用戶經過受權,能夠接着進行下一個操做。若是 id 不相同的話,將拋出 403 異常信息來拒絕訪問。

使用受權策略須要注意如下兩點:

咱們並不須要檢查 $currentUser 是否是 NULL。未登陸用戶,框架會自動爲其 全部權限 返回 false;
調用時,默認狀況下,咱們 不須要 傳遞當前登陸用戶至該方法內,由於框架會自動加載當前登陸用戶(接着看下去,後面有例子);
接下來咱們還須要在 AuthServiceProvider 類中對受權策略進行設置。AuthServiceProvider 包含了一個 policies 屬性,該屬性用於將各類模型對應到管理它們的受權策略上。咱們須要爲用戶模型 User 指定受權策略 UserPolicy。

app/Providers/AuthServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

use App\Models\User;
use App\Policies\UserPolicy;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
        User::class  => UserPolicy::class,
    ];

    /**
     * Register any application authentication / authorization services.
     *
     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate
     * @return void
     */
    public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);

        //
    }
}

受權策略定義完成以後,咱們即可以經過在用戶控制器中使用 authorize 方法來驗證用戶受權策略。默認的 AppHttpControllersController 類包含了 Laravel 的 AuthorizesRequests trait。此 trait 提供了 authorize 方法,它能夠被用於快速受權一個指定的行爲,當無權限運行該行爲時會拋出 HttpException。authorize 方法接收兩個參數,第一個爲受權策略的名稱,第二個爲進行受權驗證的數據。

咱們須要爲 edit 和 update 方法加上這行:

$this->authorize('update', $user);

書寫的位置以下:

app/Http/Controllers/UsersController.php

<?php

namespace App\Http\Controllers;
.
.
.
class UsersController extends Controller
{
    .
    .
    .
    public function edit($id)
    {
        $user = User::findOrFail($id);
        $this->authorize('update', $user);
        return view('users.edit', compact('user'));
    }

    public function update($id, Request $request)
    {
        $this->validate($request, [
            'name' => 'required|max:50',
            'password' => 'confirmed|min:6'
        ]);

        $user = User::findOrFail($id);
        
         // 受權策略判斷
        $this->authorize('update', $user);

        $data = array_filter([
            'name' => $request->name,
            'password' => $request->password,
        ]);
        $user->update($data);

        session()->flash('success', '我的資料更新成功!');

        return redirect()->route('users.show', $id);
    }
}

如今,若是你使用 id 爲 1 的用戶去訪問 id 爲 2 的用戶編輯頁面,將拋出 403 異常信息。

3、PHP中的Trait 特性及做用

PHP中的Trait 特性及做用

Traits 是一種爲相似 PHP 的單繼承語言而準備的代碼複用機制。Trait 爲了減小單繼承語言的限制,使開發人員可以自由地在不一樣層次結構內獨立的類中複用方法集

簡單使用
首先,固然是聲明個 Trait,PHP5.4 增長了 trait 關鍵字

trait first_trait {
function first_method() { /* Code Here */ }
function second_method() { /* Code Here */ }
}

同時,若是要在 Class 中使用該 Trait,那麼使用 use 關鍵字

class first_class {
// 注意這行,聲明使用 first_trait
use first_trait;
}
$obj = new first_class();
// Executing the method from trait
$obj->first_method(); // valid
$obj->second_method(); // valid

1.使用多個 Trait

trait first_trait
{
function first_method() { echo "method"; }
}
trait second_trait {
function second_method() { echo "method"; }
}
class first_class {
// now using more than one trait
use first_trait, second_trait;
}
$obj= new first_class();
// Valid
$obj->first_method(); // Print : method
// Valid
$obj->second_method(); // Print : method

2. Trait 中聲明抽象方法

咱們能夠在 Trait 中聲明須要實現的抽象方法,這樣能使使用它的 Class 必須實現它

trait first_trait {
function first_method() { echo "method"; }
// 這裏能夠加入修飾符,說明調用類必須實現它
abstract public function second_method();
}
class first_method {
use first_trait;
function second_method() {
/* Code Here */
}
}

Laravel中也應用了許多Trait方法

<?php

namespace Illuminate\Auth\Access;

trait HandlesAuthorization
{
    /**
     * Create a new access response.
     *
     * @param  string|null  $message
     * @return \Illuminate\Auth\Access\Response
     */
    protected function allow($message = null)
    {
        return new Response($message);
    }

    /**
     * Throws an unauthorized exception.
     *
     * @param  string  $message
     * @return void
     *
     * @throws \Illuminate\Auth\Access\UnauthorizedException
     */
    protected function deny($message = 'This action is unauthorized.')
    {
        throw new UnauthorizedException($message);
    }
}

Laravel中使用上邊定義好的Trait方法:
AppPoliciesUserPolicy

<?php

namespace App\Policies;

use Illuminate\Auth\Access\HandlesAuthorization;
use App\Models\User;

class UserPolicy
{
    use HandlesAuthorization;

    /**
     * Create a new policy instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }


    /**
     * 用戶更新時的權限驗證
     * @param User $currentUser
     * @param User $user
     * @return bool
     */
    public function update(User $currentUser, User $user)
    {
        return $currentUser->id === $user->id;

    }
}

相關文章:
我所理解的 PHP Trait

相關文章
相關標籤/搜索