Laravel 4:将模型从过滤器传递到控制器动作


Laravel 4: Pass model from filter to controller action

我的应用程序有三种不同的场景:

  1. 只有授权用户才能访问控制器操作
  2. 只有未经授权的用户才能访问控制器操作
  3. 任何用户都可以访问控制器操作,但已完成身份验证检查

前两个场景由简单的过滤器处理,由于所有场景在逻辑上都相似,所以似乎剩下的场景也应该由过滤器处理。

所以,我想做的是:当用户访问某个特定的控制器操作(即HomeController@getIndex)时,过滤器应检查用户是否被授权,将控制器的$user属性设置为Auth::user()值,并在所有视图之间共享该值。这是我想出的代码:

Router::filter('auth', function() {
    $route = Str::parseCallback(Route::currentRouteAction(), null); // 0 - controller name, 1 - controller action name
    $controller = App::make($route[0]);
    $user = Auth::user();
    $controller->user = $user;
    View::share('user', $user);
    return $controller->{$route[1]}();
});

此代码有效,但控制器被调用两次(即,当控制器操作没有return构造时),并且auth-filter在调用任何其他'before'过滤器之前调用控制器。

第二个解决方案:创建AuthController,并使用它的构造函数来设置$user属性,但是构造函数将被调用用于每个子控制器操作(我只想在特定操作上运行它,所以我认为过滤器是可行的)。

第三种解决方案:创建UserRepository并编写一个方法,该方法将执行所有身份验证工作,并从需要身份验证的操作中调用它(不设置$user属性)。对于几行代码来说,这种解决方案似乎有些过头了。

第四种解决方案:Auth::user()值直接传递给控制器操作(作为参数),但我还没有找到任何方便的方法。

是否有任何一种"最佳实践"解决方案可以按照描述的方式处理身份验证?有其他办法解决这个问题吗?

最佳实践可能是为每个控制器创建一个UserRepository类和服务提供程序,这些控制器将注入用户存储库,但正如您所说,对于简单的事情来说,这可能有些过头了。

也许一个更简单的解决方案是在BaseController.php中添加一个函数来设置用户。

public function setUser()
{
    $this->user = Auth::user();
}

然后,每当需要设置用户时,只需调用$controller->setUser();即可。如果您总是需要控制器来执行此操作,只需在构造函数中调用$this->setUser(),使其始终可用。

感谢@user3158900,我做了一些研究,并提出了另一个解决方案。由于将expose方法放在User模型中有点不直观,因此扩展授权外观似乎是正确的。

这是我的最终解决方案:

在app/extensions/Auth/目录中创建一个Guard类。这个类扩展了Laravel的原生Illuminate'Auth'Guard类。

<?php namespace Extensions'Auth;
class Guard extends 'Illuminate'Auth'Guard {
    public function exposeUser() {
        $user = 'Auth::user();
        'View::share('user', $user);
        return $user;
    }
}

在应用程序目录中创建一个extensions.php文件,并将该文件包含在app/global/start.php中。

require app_path().'/filters.php';
require app_path().'/extensions.php';

新的extensions.php文件包含以下代码(此代码添加了新的身份验证驱动程序):

Auth::extend('eloquent+', function() {
    return new 'Extensions'Auth'Guard(
        new 'Illuminate'Auth'EloquentUserProvider(App::make('hash'), 'Config::get('auth.model')),
        App::make('session.store')
    );
});

将auth-config的(app/config/auth.php)$model属性设置为'eloquent+'(这使我们的auth使用'eloquent+'作为auth驱动程序)。

修改composer.json以反映新的自动加载类映射。

"autoload": {
    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php",
        "app/extensions"
    ]
},

最后运行composer dump-autoload

现在,您可以像往常一样使用Auth::user()和其他身份验证方法,此外,我们还可以在视图之间共享模型,并通过在控制器操作中简单调用Auth::exposeUser()的任何操作访问它。

如果能得到一些关于这种方法的反馈也是很好的。