項目包含若干子站點,不一樣站點功能各異,但共享底層數據及邏輯。爲開發及運維效率期間,決定在一個 Laravel 應用內實現整套系統。html
本文基於 Laravel 5.2,主要介紹如何針對多站點分別進行用戶認證的改造,用意是最大限度利用 Laravel 自帶的認證系統。不過默認的認證都是根據 『email』和『password』字段進行的。以後有時間可能再追加自定義字段好比『phone』的改造方案,本文暫不涉及。laravel
爲清晰起見,項目按照不一樣站點組織成不一樣模塊。在 Laravel 原有目錄結構基礎內,分別給各個站點創設目錄。bash
laravel 5.2 project ├── app │ └── Http │ └── Controllers │ ├── Site1 │ └── Site2 └── resources └── views ├── site1 └── site2
本文以 Admin 爲例進行說明,如需增長其餘站點,進行相似改動便可。session
執行下列命令生成默認路由、控制器及視圖。app
php artisan make:auth
將默認的控制器和視圖結構分別複製到子模塊下,並建立相關模型、遷移表、修改路由、認證配置。框架
本例中,分別在 app/Http/Controllers 及 resources/views 下新建 Admin 及 admin 目錄,全部該站點相關的 Controller 及 view 均放置在上述兩目錄下。運維
最終涉及到的文件樹以下。dom
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
針對 Admin 新建 provider(下面的 admins),使用 Admin 的 Model。
針對 Admin 新建 guard,使用新建的 provider——『admins』。ide
config/auth.php
'guards' => [ 'admins' => [ 'driver' => 'session', 'provider' => 'admins', ], ], 'providers' => [ 'admins' => [ 'driver' => 'eloquent', 'model' => App\Admin::class, // 使用自定義的 Model(Admin) ], ],
Admin 站點使用 Auth 門面時均需指定 guard 爲 admins,例如得到當前登陸用戶:Auth::guard('admins')->user()。
這裏的做用固然是讓訪問 Admin 站點的請求被轉入該站點的 Controller。
本例中,不一樣系統是以站點域名來區分的,固然也能夠用別的方法。
app/Http/routes.php
Route::group(['domain' => 'admin.example.com', 'namespace' => 'Admin'], function () { // 以前將默認認證相關類保持結構複製到了 Admin 下,此時只需簡單指定公共命名空間便可 Route::auth(); // 各類註冊、登陸、找回密碼的默認路由 Route::group(['middleware' => ['auth:admins']], function () { // 指定 auth 的 guard 爲 新建的 admins Route::get('/', 'HomeController@index'); // 登陸成功才能訪問的部分放在認證保護內 }); });
咱們須要針對不一樣的站點使用不一樣的樣式或者用戶認證邏輯,因此將原 resources/views 下文件複製到 resources/views/admin 下,同時針對路徑變動修改代碼。
resources/views/vendor 因爲框架中若干處硬編碼,因此無法直接移走,用到相關的功能需另想辦法處理。
view() 方法
例如 view('auth、view('home、view('layouts、view('welcome,初始狀態下,這種形式的使用場所以下。
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 目錄下的都是經過 trait 的形式被 AppHttpControllersAuthAuthController 使用的,並且都留好了自定義屬性可供改寫,例以下方先判斷若不存在 $this->loginView,才使用默認的 auth.login。因此咱們只須要繼承默認的 AuthController 並指定這些相關屬性便可。(參見 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'); }
@include()、@extends() 方法
一樣,仍是針對 auth、home、layouts、welcome 進行處理,初始狀態下 Laravel 只使用到了 layouts.app 這個文件。
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 目錄下的只須要簡單加上前綴 admin. 便可。
vendor 目錄下的文件在運行時沒有做用,因此不用處理。
Auth 門面
因爲 Admin 站點新建了 guard,因此使用默認 Auth 門面的場合也須要更改。
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:: 來指定 guard。
vendor 目錄下的文件在運行時沒有做用,因此不用處理。
畢竟是新增的站點,參考自帶的 users/password_resets 新建相關的 table 及 model 便可。
將原 app/Http/Controllers 下相關結構複製到 Admin 下後,修改 namespace,而後針對 Admin 相關進行變更。
此處以 AuthController 爲例,PasswordController 相似:
app/Http/Controllers/Admin/Auth/AuthController.php
use App\Http\Controllers\Auth\AuthController as BaseAuthController; class AuthController extends BaseAuthController // 簡單起見直接繼承默認類 { /* 這裏的屬性都是給 trait 用的,因此不能指定爲 private */ protected $guard = 'admins'; // 指定 config/auth.php 中 guard protected $loginView = 'admin.auth.login'; // 指定登陸用 view protected $registerView = 'admin.auth.register'; // 指定註冊用 view protected function validator(array $data) // 註冊時使用的驗證規則 { return Validator::make($data, [ // 根據 Admin 所需的信息修改驗證配置 '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']), ]); } }
若是須要自定義 error 頁面(以前把 resources/views/errors 移到 resources/views/admin/errors)的狀況下,因爲 Laravel 的異常固定由 AppExceptionsHandler 處理,因此須要在此類中針對不一樣站點分別指定錯誤處理 view。具體來講是修改指定錯誤頁的邏輯,在子類中根據請求的域名(本例的區分規則)指定該站點的錯誤頁 view。
app/Exceptions/Handler.php
class Handler extends ExceptionHandler { protected $host; public function render($request, Exception $e) { $this->host = $request->getHost(); // 記錄請求站點的域名 return parent::render($request, $e); } protected function renderHttpException(HttpException $e) // 修改並覆蓋父類的方法,用於指定子站點錯誤頁 view { switch($this->host) { case 'admin.example.com': // 針對 Admin 站點指定路徑中的 admin $prefix = 'admin'; break; } $prefix = empty($prefix) ? '' : $prefix . '.'; $status = $e->getStatusCode(); $errorView = $prefix . "errors.{$status}"; // 指定錯誤頁 view if (view()->exists($errorView)) { return response()->view($errorView, ['exception' => $e], $status, $e->getHeaders()); } else { return $this->convertExceptionToResponse($e); } } }
整個改造過程當中,主要參考了以下資料來源,感謝各位做者的同時也一併放出參考。