将 'auth' 中间件与子域一起使用

Using 'auth' middleware with subdomains

我试图通过 auth 中间件在我的控制器中传递某些功能。但是,与这些功能关联的路由需要 URL 中的子域才能工作。这些函数在未通过中间件传递或通过定制中间件传递时似乎可以正常工作,但 'auth' 中间件会抛出错误:

UrlGenerationException UrlGenerationException.php 第 17 行: 缺少 [Route: login] [URI: login] 所需的参数。

这类似于当我尝试 运行 参数列表中没有 $account 变量的函数时抛出的错误(因为它需要一个带有路由的子域)。

深入研究 'auth' 中间件调用的 Authenticate class 后,我发现导致错误的行在 public 函数 authenticate( array $guards) 如下所示。

protected function authenticate(array $guards)

{
    if (empty($guards)) {
        /** ANYTHING BEFORE THIS RETURN STATEMENT RUNS WITH NO ERRORS **/
        return $this->auth->authenticate();
    }

    foreach ($guards as $guard) {
        if ($this->auth->guard($guard)->check()) {
            return $this->auth->shouldUse($guard);
        }
    }

    throw new AuthenticationException('Unauthenticated.', $guards);
}

以下是我的一些代码供参考(只包含相关代码片段):

路线文件

routes\web.php

Route::group(['domain' => '{account}.'.env('APP_URL')], function () {
  include('appRoutes/bcm.php');
});

routes\appRoutes\bcm.php

/********************************************/
/*********STATIC PAGE ROUTES******************/
/********************************************/

Route::get('/boards-commissions', 'BCM\PagesController@home');


/********************************************/
/*********BOARD ROUTES***********************/
/********************************************/

Route::get('/boards-commissions/boards', 'BCM\BoardsController@index');

Route::get('/boards-commissions/boards/archive/index', 
'BCM\BoardsController@archiveIndex');

控制器

app\Http\Controllers\BCM\BoardsController.php

namespace App\Http\Controllers\BCM;

use Auth;
use Session;
use Validator;

use Illuminate\Http\Request;
use Illuminate\Foundation\Validation\ValidatesRequests;

//Models
use App\Models\BCM\Board;

class BoardsController extends Controller
{
    public function __construct()
    {
        $this->middleware('bcm_app_access');
        $this->middleware('auth', ['except' => array('index', 'show')]);
        $this->middleware('bcm_admin', ['only' => array('edit', 'update', 
'create', 'store', 'archive', 'showArchive', 'showArchivedBoard', 'restore')]);
    }

    public function index($account, Request $request) {
        $boards = Board::all();
        $user = $request->user();
        return view('bcm.boards.index')->with('boards', $boards)->with('user', $user);
    }

    public function archiveIndex($account, Request $request) {
        $boards = Board::all();
        $user = $request->user();
        return view('bcm.boards.archiveList')->with('boards', $boards)->with('user', $user);
    }
}

目前看来只有auth中间件没有起作用。索引函数 运行 很好(因为它在控制器的构造中被排除在 auth 中间件之外)即使它正在通过 bcm_app_access 中间件传递。但是archiveIndex在经过auth中间件的时候会抛出上面提到的UrlGenerationException错误。

我觉得 $account 参数需要添加或包含在某个地方,以便 auth 中间件知道它需要引用它,但我不确定在哪里添加它,我不知道$this->auth->authenticate(); 时引用了哪些其他文件;是 运行 所以我不知道在哪里添加它。有什么想法吗?

在最初的问题中,我想知道如何让 'auth' 中间件与子域一起工作。我仍然没有想出这样做,但我已经通过创建一个基本的自定义中间件建立了一个功能性的解决方法。 authenticate 中间件的目的是检查该站点的用户是否已登录或 运行 作为访客。为了模仿这个功能,我通过 运行

创建了一个中间件
php artisan make:middleware SubdomainAuth

在命令行中。然后我将自动生成的中间件文件配置为如下所示:

<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
class SubdomainAuth
{
    /**
     * Handle an incoming request to make sure that a valid user is logged in.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next) {
        $user = Auth::user();
        if ($user == null) {
          return redirect('/login');
        }
        return $next($request);
    }
}

最后,我通过添加行

配置我的内核以识别新的中间件
'sub_auth' => \App\Http\Middleware\SubdomainAuth::class,

到app/Http/Kernel.php。从那里我可以用我创建的 sub_auth 中间件替换我控制器中的 auth 中间件。我上面问题的例子现在看起来像这样:

namespace App\Http\Controllers\BCM;

use Auth;
use Session;
use Validator;

use Illuminate\Http\Request;
use Illuminate\Foundation\Validation\ValidatesRequests;

//Models
use App\Models\BCM\Board;

class BoardsController extends Controller
{
    public function __construct()
    {
        $this->middleware('bcm_app_access');
        $this->middleware('sub_auth', ['except' => array('index', 'show')]);
        $this->middleware('bcm_admin', ['only' => array('edit', 'update', 
'create', 'store', 'archive', 'showArchive', 'showArchivedBoard', 'restore')]);
    }

    public function index($account, Request $request) {
        $boards = Board::all();
        $user = $request->user();
        return view('bcm.boards.index')->with('boards', $boards)->with('user', $user);
    }

    public function archiveIndex($account, Request $request) {
        $boards = Board::all();
        $user = $request->user();
        return view('bcm.boards.archiveList')->with('boards', $boards)->with('user', $user);
    }
}

此变通方法成功筛选出未登录的用户并将他们重定向到登录页面。但是,我对 Authenticate 中间件的工作方式还不够熟悉,无法知道我创建的 SubdomainAuth class 中是否缺少我的自定义 class 所增加的安全性。

我遇到过同样的问题。这是我的解决方案:

Laravel 的 Auth 中间件使用其默认路由('login')处理它,它位于 \Illuminate\Foundation\Exceptions\Handler.php

protected function unauthenticated($request, AuthenticationException $exception)
{
    return $request->expectsJson()
                ? response()->json(['message' => $exception->getMessage()], 401)
                : redirect()->guest(route('login'));
}

您可以在此处修改以更改 route('login', 'subdomain') 以使其正常工作。但就个人而言,我想保持框架不变。我修改了异常处理程序而不是覆盖“unauthenticated”函数。

在\app\Exceptions\Handler中添加一个新函数。php

protected function unauthenticated($request, AuthenticationException $exception)
{
    $subdomain = explode("//",explode('.', $request->url())[0])[1];
    return $request->expectsJson()
                ? response()->json(['message' => $exception->getMessage()], 401)
                : redirect()->guest(route('login',$subdomain));
}

我已经使用 $request 获取 url 并提取它。我认为如果您可以更深入地研究 userResolver,您将能够提取在 routes/web.php 中定义的子域变量,但我我现在对此很满意。

粗略的laravel7指南:

您的子域的通配符参数{brand}

Route::domain( '{brand}.' . parse_url(config('app.url'), PHP_URL_HOST) )->group(function () {

    // login page
    Route::get('/login', 'Auth\LoginController@showLoginForm')->name('login')->middleware('guest');

    Route::middleware('auth')->group(function () {
        Route::get('/', 'BrandController@showDashboard')->name('dashboard');
        
        ...
    }
});

将在 $request 对象中可访问,因此在:

// app\Http\Middleware\Authenticate.php

protected function redirectTo($request)
{
    if (! $request->expectsJson()) {
        return route('login', $request->brand);
    }
}

只需将您的通配符作为参数传递给路由函数