我的应用程序有三种不同的场景:
- 只有授权用户才能访问控制器操作
- 只有未经授权的用户才能访问控制器操作
- 任何用户都可以访问控制器操作,但已完成身份验证检查
前两个场景由简单的过滤器处理,由于所有场景在逻辑上都相似,所以似乎剩下的场景也应该由过滤器处理。
所以,我想做的是:当用户访问某个特定的控制器操作(即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()
的任何操作访问它。
如果能得到一些关于这种方法的反馈也是很好的。