【Laravel】多用戶認(rèn)證系統(tǒng)改造方案

2016-08-17 補(bǔ)充 Exception 部分改造方案的內(nèi)容
2016-08-13 補(bǔ)充 View 部分改造方案的內(nèi)容

背景

項(xiàng)目包含若干子站點(diǎn),不同站點(diǎn)功能各異燎潮,但共享底層數(shù)據(jù)及邏輯倔丈。為開(kāi)發(fā)及運(yùn)維效率期間憨闰,決定在一個(gè) Laravel 應(yīng)用內(nèi)實(shí)現(xiàn)整套系統(tǒng)。

本文基于 Laravel 5.2需五,主要介紹如何針對(duì)多站點(diǎn)分別進(jìn)行用戶認(rèn)證的改造鹉动,用意是最大限度利用 Laravel 自帶的認(rèn)證系統(tǒng)。不過(guò)默認(rèn)的認(rèn)證都是根據(jù) 『email』和『password』字段進(jìn)行的宏邮。之后有時(shí)間可能再追加自定義字段比如『phone』的改造方案泽示,本文暫不涉及缸血。


具體方案

為清晰起見(jiàn),項(xiàng)目按照不同站點(diǎn)組織成不同模塊械筛。在 Laravel 原有目錄結(jié)構(gòu)基礎(chǔ)內(nèi)捎泻,分別給各個(gè)站點(diǎn)創(chuàng)設(shè)目錄。

laravel 5.2 project
├── app
│   └── Http
│       └── Controllers
│           ├── Site1
│           └── Site2
└── resources
    └── views
        ├── site1
        └── site2

本文以 Admin 為例進(jìn)行說(shuō)明埋哟,如需增加其他站點(diǎn)笆豁,進(jìn)行類似改動(dòng)即可。

Structure

執(zhí)行下列命令生成默認(rèn)路由定欧、控制器及視圖渔呵。

php artisan make:auth

將默認(rèn)的控制器和視圖結(jié)構(gòu)分別復(fù)制到子模塊下,并創(chuàng)建相關(guān)模型砍鸠、遷移表扩氢、修改路由、認(rèn)證配置爷辱。

本例中录豺,分別在 app/Http/Controllers 及 resources/views 下新建 Admin 及 admin 目錄,所有該站點(diǎn)相關(guān)的 Controller 及 view 均放置在上述兩目錄下饭弓。

最終涉及到的文件樹(shù)如下双饥。

laravel 5.2 project
├── app
│   ├── Exceptions
│   │   └── Handler.php (變更)
│   ├── Http
│   │   ├── Controllers
│   │   │   └── Admin (新建)
│   │   │       ├── Auth
│   │   │       │   ├── AuthController.php
│   │   │       │   └── PasswordController.php
│   │   │       └── HomeController.php
│   │   └── routes.php (變更)
│   └── Admin.php (新建)
├── config
│   └── auth.php (變更)
├── database
│   └── migrations
│       ├── 2014_10_12_000000_create_admins_table.php (新建)
│       └── 2014_10_12_100000_create_admin_password_resets_table.php (新建)
└── resources
    └── views
        └── admin (新建)
            ├── auth
            │   ├── emails
            │   │   └── password.blade.php
            │   ├── login.blade.php
            │   ├── passwords
            │   │   ├── email.blade.php
            │   │   └── reset.blade.php
            │   └── register.blade.php
            ├── errors
            │   └── 503.blade.php
            ├── home.blade.php
            ├── layouts
            │   └── app.blade.php
            └── welcome.blade.php

Config

針對(duì) Admin 新建 provider(下面的 admins),使用 Admin 的 Model弟断。
針對(duì) Admin 新建 guard咏花,使用新建的 provider——『admins』。

config/auth.php

'guards' => [
    'admins' => [
        'driver' => 'session',
        'provider' => 'admins',
    ],
],
'providers' => [
    'admins' => [
        'driver' => 'eloquent',
        'model' => App\Admin::class, // 使用自定義的 Model(Admin)
    ],
],

Admin 站點(diǎn)使用 Auth 門面時(shí)均需指定 guard 為 admins阀趴,例如獲得當(dāng)前登錄用戶:Auth::guard('admins')->user()昏翰。

Router

這里的作用當(dāng)然是讓訪問(wèn) Admin 站點(diǎn)的請(qǐng)求被轉(zhuǎn)入該站點(diǎn)的 Controller。
本例中刘急,不同系統(tǒng)是以站點(diǎn)域名來(lái)區(qū)分的棚菊,當(dāng)然也可以用別的方法。

app/Http/routes.php

Route::group(['domain' => 'admin.example.com', 'namespace' => 'Admin'], function () { // 之前將默認(rèn)認(rèn)證相關(guān)類保持結(jié)構(gòu)復(fù)制到了 Admin 下叔汁,此時(shí)只需簡(jiǎn)單指定公共命名空間即可
    Route::auth(); // 各種注冊(cè)统求、登錄、找回密碼的默認(rèn)路由
    Route::group(['middleware' => ['auth:admins']], function () { // 指定 auth 的 guard 為 新建的 admins
        Route::get('/', 'HomeController@index'); // 登錄成功才能訪問(wèn)的部分放在認(rèn)證保護(hù)內(nèi)
    });
});

View

我們需要針對(duì)不同的站點(diǎn)使用不同的樣式或者用戶認(rèn)證邏輯据块,所以將原 resources/views 下文件復(fù)制到 resources/views/admin 下码邻,同時(shí)針對(duì)路徑變更修改代碼。

resources/views/vendor 由于框架中若干處硬編碼另假,所以沒(méi)法直接移走冒滩,用到相關(guān)的功能需另想辦法處理。

  1. view() 方法
    例如 view('auth浪谴、view('home开睡、view('layouts因苹、view('welcome,初始狀態(tài)下篇恒,這種形式的使用場(chǎng)所如下扶檐。
app/Http/Controllers/HomeController.php:27:        return view('home');
app/Http/routes.php:15:    return view('welcome');
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/controllers/HomeController.stub:27:        return view('home');
vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php:37:        return view('auth.login');
vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.php:33:        return view('auth.register');
vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetsPasswords.php:49:            return view('auth.passwords.email');
vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetsPasswords.php:52:        return view('auth.password');
vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetsPasswords.php:194:            return view('auth.passwords.reset')->with(compact('token', 'email'));
vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetsPasswords.php:197:        return view('auth.reset')->with(compact('token', 'email'));

app 目錄下的 view 直接加上 admin. 的前綴就好。
vendor 目錄下的都是通過(guò) trait 的形式被 App\Http\Controllers\Auth\AuthController 使用的胁艰,而且都留好了自定義屬性可供改寫(xiě)款筑,例如下方先判斷若不存在 $this->loginView,才使用默認(rèn)的 auth.login腾么。所以我們只需要繼承默認(rèn)的 AuthController 并指定這些相關(guān)屬性即可奈梳。(參見(jiàn) Controller 部分介紹)

vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php

public function showLoginForm()
{
    $view = property_exists($this, 'loginView')
                ? $this->loginView : 'auth.authenticate';

    if (view()->exists($view)) {
        return view($view);
    }

    return view('auth.login');
}
  1. @include()@extends() 方法
    同樣解虱,還是針對(duì) auth攘须、home、layouts殴泰、welcome 進(jìn)行處理于宙,初始狀態(tài)下 Laravel 只使用到了 layouts.app 這個(gè)文件。
resources/views/auth/login.blade.php:1:@extends('layouts.app')
resources/views/auth/passwords/email.blade.php:1:@extends('layouts.app')
resources/views/auth/passwords/reset.blade.php:1:@extends('layouts.app')
resources/views/auth/register.blade.php:1:@extends('layouts.app')
resources/views/home.blade.php:1:@extends('layouts.app')
resources/views/welcome.blade.php:1:@extends('layouts.app')
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub:1:@extends('layouts.app')
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub:1:@extends('layouts.app')
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub:1:@extends('layouts.app')
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub:1:@extends('layouts.app')
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/home.stub:1:@extends('layouts.app')
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/welcome.stub:1:@extends('layouts.app')

resources 目錄下的只需要簡(jiǎn)單加上前綴 admin. 即可悍汛。
vendor 目錄下的文件在運(yùn)行時(shí)沒(méi)有作用捞魁,所以不用處理。

  1. Auth 門面
    由于 Admin 站點(diǎn)新建了 guard离咐,所以使用默認(rèn) Auth 門面的場(chǎng)合也需要更改谱俭。
resources/views/layouts/app.blade.php:56:                    @if (Auth::guest())
resources/views/layouts/app.blade.php:62:                                {{ Auth::user()->name }} <span class="caret"></span>
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub:56:                    @if (Auth::guest())
vendor/laravel/framework/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub:62:                                {{ Auth::user()->name }} <span class="caret"></span>

resources 目錄下,用 Admin::guard('admins')-> 替換 Auth:: 來(lái)指定 guard宵蛀。
vendor 目錄下的文件在運(yùn)行時(shí)沒(méi)有作用旺上,所以不用處理。

Migration & Model

畢竟是新增的站點(diǎn)糖埋,參考自帶的 users/password_resets 新建相關(guān)的 table 及 model 即可。

Controller

將原 app/Http/Controllers 下相關(guān)結(jié)構(gòu)復(fù)制到 Admin 下后窃这,修改 namespace瞳别,然后針對(duì) Admin 相關(guān)進(jìn)行變動(dòng)。

此處以 AuthController 為例杭攻,PasswordController 類似:

app/Http/Controllers/Admin/Auth/AuthController.php

use App\Http\Controllers\Auth\AuthController as BaseAuthController;

class AuthController extends BaseAuthController // 簡(jiǎn)單起見(jiàn)直接繼承默認(rèn)類
{

    /* 這里的屬性都是給 trait 用的祟敛,所以不能指定為 private */
    protected $guard = 'admins'; // 指定 config/auth.php 中 guard
    protected $loginView = 'admin.auth.login'; // 指定登錄用 view
    protected $registerView = 'admin.auth.register'; // 指定注冊(cè)用 view

    protected function validator(array $data) // 注冊(cè)時(shí)使用的驗(yàn)證規(guī)則
    {
        return Validator::make($data, [ // 根據(jù) Admin 所需的信息修改驗(yàn)證配置
            'name' => 'required|max:255',
            'email' => 'required|email|max:255|unique:admins', // 使用 admins 表
            'password' => 'required|confirmed|min:6',
            'terms' => 'required',
        ]);
    }

    protected function create(array $data)
    {
        return Admin::create([ // 使用自定義的 Model(Admin)
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
    }
}

Exception

如果需要自定義 error 頁(yè)面(之前把 resources/views/errors 移到 resources/views/admin/errors)的情況下,由于 Laravel 的異常固定由 App\Exceptions\Handler 處理兆解,所以需要在此類中針對(duì)不同站點(diǎn)分別指定錯(cuò)誤處理 view馆铁。具體來(lái)說(shuō)是修改指定錯(cuò)誤頁(yè)的邏輯,在子類中根據(jù)請(qǐng)求的域名(本例的區(qū)分規(guī)則)指定該站點(diǎn)的錯(cuò)誤頁(yè) view锅睛。

app/Exceptions/Handler.php

class Handler extends ExceptionHandler
{
    protected $host;

    public function render($request, Exception $e)
    {
        $this->host = $request->getHost(); // 記錄請(qǐng)求站點(diǎn)的域名
        return parent::render($request, $e);
    }

    protected function renderHttpException(HttpException $e) // 修改并覆蓋父類的方法埠巨,用于指定子站點(diǎn)錯(cuò)誤頁(yè) view
    {
        switch($this->host)
        {
            case 'admin.example.com': // 針對(duì) Admin 站點(diǎn)指定路徑中的 admin 
                $prefix = 'admin';
                break;
        }
        $prefix = empty($prefix) ? '' : $prefix . '.';

        $status = $e->getStatusCode();
        $errorView = $prefix . "errors.{$status}"; // 指定錯(cuò)誤頁(yè) view
        
        if (view()->exists($errorView)) {
            return response()->view($errorView, ['exception' => $e], $status, $e->getHeaders());
        } else {
            return $this->convertExceptionToResponse($e);
        }
    }
}

參考

整個(gè)改造過(guò)程中历谍,主要參考了如下資料來(lái)源,感謝各位作者的同時(shí)也一并放出參考辣垒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末望侈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子勋桶,更是在濱河造成了極大的恐慌脱衙,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件例驹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鹃锈,警方通過(guò)查閱死者的電腦和手機(jī)荤胁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仪召,“玉大人寨蹋,你說(shuō)我怎么就攤上這事∪用” “怎么了已旧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)召娜。 經(jīng)常有香客問(wèn)我运褪,道長(zhǎng),這世上最難降的妖魔是什么玖瘸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任秸讹,我火速辦了婚禮,結(jié)果婚禮上雅倒,老公的妹妹穿的比我還像新娘璃诀。我一直安慰自己,他們只是感情好蔑匣,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布劣欢。 她就那樣靜靜地躺著,像睡著了一般裁良。 火紅的嫁衣襯著肌膚如雪凿将。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天价脾,我揣著相機(jī)與錄音牧抵,去河邊找鬼。 笑死侨把,一個(gè)胖子當(dāng)著我的面吹牛犀变,可吹牛的內(nèi)容都是我干的妹孙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼弛作,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涕蜂!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起映琳,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤机隙,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后萨西,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體有鹿,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年谎脯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了葱跋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡源梭,死狀恐怖娱俺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情废麻,我是刑警寧澤荠卷,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站烛愧,受9級(jí)特大地震影響油宜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怜姿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一慎冤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沧卢,春花似錦蚁堤、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至熟空,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間搞莺,已是汗流浹背息罗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留才沧,地道東北人迈喉。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓绍刮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親挨摸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子孩革,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容