资讯专栏INFORMATION COLUMN

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

paulli3 / 2500人阅读

摘要:本文基于,主要介绍如何针对多站点分别进行用户认证的改造,用意是最大限度利用自带的认证系统。具体方案为清晰起见,项目按照不同站点组织成不同模块。学院版用户认证文档版用户认证文档更详细学院版验证文档版验证文档更详细翁航版多用户认证方案

原文发表于 http://www.jianshu.com/p/d6c112f27661

背景

项目包含若干子站点,不同站点功能各异,但共享底层数据及逻辑。为开发及运维效率期间,决定在一个 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
│   ├── 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

针对 Admin 新建 provider(下面的 admins),使用 Admin 的 Model。
针对 Admin 新建 guard,使用新建的 provider——『admins』。

config/auth.php

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

Admin 站点使用 Auth 门面时均需指定 guard 为 admins,例如获得当前登录用户:Auth::guard("admins")->user()。

Router

这里的作用当然是让访问 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"); // 登录成功才能访问的部分放在认证保护内
    });
});
View

我们需要针对不同的站点使用不同的样式或者用户认证逻辑,所以将原 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 }} 
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 }} 

resources 目录下,用 Admin::guard("admins")-> 替换 Auth:: 来指定 guard。
vendor 目录下的文件在运行时没有作用,所以不用处理。

Migration & Model

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

Controller

将原 app/Http/Controllers 下相关结构复制到 Admin 下后,修改 namespace,然后针对 Admin 相关进行变动。

此处以 AuthController 为例,PasswordController 类似:

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

use AppHttpControllersAuthAuthController 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"]),
        ]);
    }
}
Exception

如果需要自定义 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);
        }
    }
}

参考

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

Laravel学院版用户认证文档

Dearmadman版用户认证文档(更详细)

Laravel学院版验证文档

Dearmadman版验证文档(更详细)

Sun_翁航版多用户认证方案

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21896.html

相关文章

  • Laravel 用户字段认证优雅解决方案

    摘要:弊端显而易见,如果另一个不是就抓瞎了,下面是另一种通用的解决方案在中重写方法假设字段是假设字段是假设字段是可以看到虽然能解决问题,但是显然有悖于的优雅风格,卖了这么多关子,下面跟大家分享一下我的解决方案。 解决方案: 登录字段不超过两个的(简单的解决方案) 登录字段大于或等于三个的(相对复杂一些) 登录字段不超过两个的 我在网上看到一种相对简单解决方案,但是不能解决所有两个字段的验...

    jk_v1 评论0 收藏0
  • 下载量最高 100 个 Laravel 扩展包推荐

    摘要:本文经授权转自社区,后续更新将以帖子内容和内容为准。说明另一个令人喜欢的地方,是拥有活跃的开发者社区,而活跃的开发者社区带来的,是繁华的扩展包生态。本文对上打了标签的扩展包进行整理,截止到现在年月号,有超过个扩展包,以下是下载量最大的个。 本文经授权转自 PHPHub 社区,后续更新将以 PHPHub 帖子内容 和 GitHub 内容 为准。 说明 Laravel 另一个令人喜欢的地方...

    Tychio 评论0 收藏0
  • PHP / Laravel API 开发推荐阅读清单

    showImg(https://segmentfault.com/img/bV6aHV?w=1280&h=800); 社区优秀文章 Laravel 5.5+passport 放弃 dingo 开发 API 实战,让 API 开发更省心 - 自造车轮。 API 文档神器 Swagger 介绍及在 PHP 项目中使用 - API 文档撰写方案 推荐 Laravel API 项目必须使用的 8 个...

    shmily 评论0 收藏0
  • Laravel 技巧之 定时任务

    摘要:对于定时任务的基本用法,官网文档已经描述得很详细了,这里不再多说。这种情况下如果定时任务能够并行执行,就不会有这样的问题。这个时候我们希望能够像队列那样,将定时任务分散到多台服务器上。 定时任务 Scheduled Tasks 是 Laravel 提供的组件之一,稍微上点规模的项目应该都会用到,比如开发微信应用时通过定时任务去刷新access token,比如每天定时发推送提现用户要记...

    keithyau 评论0 收藏0
  • Laravel 获取当前 Guard 分析 —源自电商购物车的实际需求

    摘要:因为客户希望能够直观的看到目前购物车中商品信息,以便推送优惠信息来促使转化。用户在商城中的购物车数据导购使用导购小程序代用户下单或结账时加入的购物车数据,不和用户购物车数据同步。 iBrand 产品中关于购物车的需求比较复杂,我们基于 overture/laravel-shopping-cart 扩展出了更加符合电商需求的购物车包,之前有文章进行过简单的介绍: Laravel shop...

    daydream 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<