【Laravel】多用户认证系统改造方案

1,961 阅读3分钟
原文链接: www.jianshu.com

背景

项目包含若干子站点,不同站点功能各异,但共享底层数据及逻辑。为开发及运维效率期间,决定在一个 Laravel 应用内实现整套系统。

本文基于 Laravel 5.2,主要介绍如何针对多站点分别进行用户认证的改造,用意是最大限度利用 Laravel 自带的认证系统。不过默认的认证都是根据 『email』和『password』字段进行的。之后有时间可能再追加自定义字段比如『phone』的改造方案,本文暂不涉及。

具体方案

为清晰起见,项目按照不同子系统组织成不同模块。在 Laravel 原有目录结构基础内,分别给子系统

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

本文以 Admin 为例进行说明,如需增加其他子系统,进行类似改动即可。

Structure

执行下列命令生成默认路由、控制器及视图。

php artisan make:auth

将默认的控制器和视图结构分别复制到子模块下,并创建相关模型、迁移表、修改路由、认证配置。

本例中,分别在 app/Http/Controllers 及 resources/views 下新建 Admin 及 admin 目录,所有该子系统相关的 Controller 及 view 均放置在上述两目录下。

最终涉及到的文件树如下。

laravel 5.2 project
├── app
│   ├── 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_admins_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

Config

针对 Admin 新建 provider,使用 Admin 的 Model 或 table。
针对 Admin 新建 guard,使用新建的 provider。
之后会在 Admin 的认证 Controller 中指定此 guard 使用。

config/auth.php

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

Router

这里的作用当然是让访问 Admin 子系统的请求被转入该子系统的 Controller。
本例中子系统是以域名来区分的,当然也可以用别的方法。

app/Http/routes.php

Route::group(['domain' => 'admin.example.com', 'namespace' => 'Admin'], function () { // 之前将默认认证相关类保持结构复制到了 Admin 下,此时只需简单指定公共命名空间即可
    Route::auth(); // 各种注册、登录、找回密码的默认路由
    Route::group(['middleware' => ['auth']], function () {
        Route::get('/', 'HomeController@index'); // 登录成功才能访问的部分放在认证保护内
    });
});

View

系统默认会使用 resource/view/auth 下的blade,我们需要针对不同的用户使用不同的样式,所以需要改变这些默认路径。改动时需要注意包含下列两种形式的代码:

  1. view('auth.
    初始状态下,这种形式只在 Laravel 的框架文件中使用。

    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'));

    这些都是通过 trait 的形式被 App\Http\Controllers\Auth\AuthController 使用的。
    而且都留好了自定义属性可供改写,例如下方先判断若不存在 $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');
    }
  2. @include('auth.
    初始状态下,并没使用这种形式,不过如果使用了 acacha/adminlte-laravel,会在 resources/views/auth 下各模板文件中用到。总之我们将其统一改为 @include('admin.auth. 即可。

Migration & Model

毕竟是新增的子系统,参考自带的 users/password_resets 新建相关的 table 及 model 即可。

Controller

将原 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']),
        ]);
    }
}

参考

整个改造过程中,主要参考了如下资料来源,感谢各位作者的同时也一并放出参考。