foothing / laravel-wrappr
将权限绑定到Laravel路由。
Requires
- php: >=5.4.0
- foothing/laravel-repository: >=0.7
- illuminate/auth: ~5.1
- illuminate/cache: ~5.1
- illuminate/database: ~5.1
Requires (Dev)
- codeclimate/php-test-reporter: dev-master
- mockery/mockery: 0.9.*
- orchestra/testbench: 3.1.*
- phpunit/phpunit: 4.*
README
对于Laravel 5.1,请使用0.4.10版本
对于Laravel 5.2及以上版本,请使用最新的0.x版本
这是一个旨在简化将路由绑定到权限过程的Laravel 5包,它独立于特定的权限处理器,即使您的权限处理器不支持此功能,也允许添加路由检查。
此外,它还试图在基本操作方面将您的应用程序与权限处理器解耦。
有一个锁定集成可立即使用。
我还计划实现一个Gate集成,如果您对此感兴趣,请随时留言。
用法示例
在您想要限制路由访问到read.users权限的基本用例中
Route::get('api/users/{id?}', ['middleware:wrappr.check:read.users,user,{id}', function() { // Access is allowed to users with the 'read.users' permission on // the 'user' resource with the {id} identifier }]);
或者,您可以为动态URL定义自定义路由模式,前提是您已经定义了控制器,并希望在方法上分割访问逻辑。
Route::controller('api/v1/{args?}', 'FooController');
假设您的控制器提供了以下路由
GET /api/v1/resources/users GET /api/v1/resources/posts POST /api/v1/services/publish/post
您可以定义如下规则来限制访问
[ 'verb' => 'put', 'path' => 'api/v1/resources/posts/{id}', 'permissions' => ['posts.create', 'posts.update'], 'resource' => 'post', ],
内容
概念
由于您可能需要在某个时候切换到另一个acl库,因此我已经努力添加了一个抽象层,可以使您的应用程序更容易维护。此包试图以两种不同的方式抽象您的应用程序与acl层
- 基于路由的检查标准方法
- 基本acl操作的标准API
为了访问权限检查,必须设置一个充当acl库桥接器的权限提供者。此外,还需要一个用户提供者来检索认证用户。
虽然路由检查是这个项目的重点,但acl操作功能尽量不干涉,您可以随意使用它。
安装和设置
Composer安装
"require": [
"foothing/laravel-wrappr": "0.*"
]
在您的config/app.php提供者数组中添加服务提供者。
'providers' => [ // ... Foothing\Wrappr\WrapprServiceProvider::class ]
然后发布包配置和迁移文件
php artisan vendor:publish --provider="Foothing\Wrappr\WrapprServiceProvider"
配置提供者
发布配置文件后,您可以根据项目设置配置一个用户提供者和一个权限提供者。此示例配置将启用与Lock和Illuminate\Auth\Guard的集成。
在您的config/wrappr.php
'permissionsProvider' => 'Foothing\Wrappr\Lock\LockProvider', 'usersProvider' => 'Foothing\Wrappr\Providers\Users\DefaultProvider',
在Laravel路由器中使用
此包有两种用法,每种用法都由自己的中间件实现。让我们看看默认情况。首先,您需要设置中间件在您的App\Http\Kernel中。
添加以下行
protected $routeMiddleware = [ 'wrappr.check' => 'Foothing\Wrappr\Middleware\CheckRoute', ];
使用CheckRoute中间件来控制对以下routes.php中的路由的访问
Route::get('api/users', ['middleware:wrappr.check:admin.users', function() { // Access is allowed for the users with the 'admin.users' permission }]);
CheckRoute中间件接受3个参数
- 所需权限
- 可选的资源名称,例如“user”
- 一个可选的资源标识符(整数)
示例
Route::get('api/users/{id?}', ['middleware:wrappr.check:read.users,user,1', function() { // Access is allowed for the users with the 'read.users' permission on // the 'user' resource with the {id} identifier }]);
此外,中间件可以处理您的路由参数。请考虑以下内容
Route::get('api/users/{id?}', ['middleware:wrappr.check:read.users,user,{id}', function() { // Access is allowed for the users with the 'read.users' permission on // the 'user' resource with the {id} identifier }]);
当您在括号内传递资源标识符时,中间件将自动尝试从HTTP请求中检索值。
与自定义路由一起使用
当您无法在路由定义级别精细控制时,有另一种处理权限的方法。考虑以下全局RESTful控制器
Route::controller('api/v1/{args?}', 'FooController');
假设您的控制器使用变量模式来处理路由,例如
GET /api/v1/resources/users GET /api/v1/resources/posts POST /api/v1/services/publish/post
在这种情况下,您无法使用先前的方法绑定权限,因此CheckPath中间件可以提供帮助。为了启用此行为,您需要执行一些额外的设置步骤。
第一步是运行您之前发布的迁移。
php artisan migrate
然后您有两个选择。
使用配置文件安装路由
现在您可以在您的config/wrappr.php中配置您想要置于授权控制下的路由,编辑您的routes部分
'routes' => [ [ // Allowed values are 'get', 'post', 'put', 'delete' // or the '*' wildcard to enable all verbs. 'verb' => 'post', // The url path we want to restrict access to. 'path' => 'foo', // The required permissions for the given path. 'permissions' => 'bar', ], // This configuration will control the access to the // POST:api/v1/resources/users action, which will be // only allowed for users with the 'admin.account' permission [ 'verb' => 'post', 'path' => 'api/v1/resources/users', 'permissions' => 'admin.account', ], // This configuration will control the access to the // PUT:api/v1/resources/posts/{id} action, which will be // only allowed for users with both the 'posts.create' and // 'posts.update' permissions on the 'post' resource with // the {id} identifier. [ 'verb' => 'put', 'path' => 'api/v1/resources/posts/{id}', 'permissions' => ['posts.create', 'posts.update'], 'resource' => 'post', ], // In this case the 'admin/' nested routes // will be granted access only when the 'admin' permission // is available to the current auth user. [ 'verb' => '*', 'path' => 'admin/*', 'permissions' => ['admin'], ], // You can also use the path wildcard in this way, // therefore requiring the 'superadmin' permission // for each route starting with 'admin'. [ 'verb' => '*', 'path' => 'admin*', 'permissions' => ['superadmin'], ], ],
完成路由设置后,运行Artisan命令
php artisan wrappr:install
请注意,每次您更改路由配置时,都应在Artisan命令中再次运行以刷新它们。
程序化安装路由
或者,您可以使用RouteInstaller来程序化设置您的路由。在这种情况下,您不需要Artisan命令。
$installer = \App::make('foothing.wrappr.installer'); $installer ->route('get', '/api/v1/*')->requires('api.read') ->route('put', '/api/v1/*')->requires('api.write') ->route('delete', '/api/v1/users/{id}/*')->requires('api.write,api.read')->on('users') ->install(); // Use wildcard $installer->route('*', '/admin')->requires->('admin.access');
设置中间件
将全局中间件添加到您的App\Http\Kernel中,如下所示
protected $middleware = [ \Foothing\Wrappr\Middleware\CheckPath::class ];
然后您就设置好了。
关于路由处理顺序的说明
中间件将解析所有传入的HTTP请求以匹配您安装的路由,并且将做出如下反应
- 如果找不到路由模式,则访问被允许
- 如果找到路由模式,它将触发权限提供者以执行检查
一旦您安装了路由,请记住,它们将按层次顺序处理,从更具体的到更通用的。看以下示例
api/v1/users/{id}/*
api/v1/users/{id}
api/v1/*
api/v1
api/*
这会导致以下行为
- 如果您请求
foo/bar路由未找到,因此访问被允许 - 如果您请求
api/foo,则绑定到api/*模式的权限将被应用 - 如果您请求
api/v1,则绑定到api/v1模式的权限将被应用
依此类推。
中间件响应
这两个中间件实现都会在失败时返回HTTP 401,并带有额外的X-Reason: permission头部,这对于处理客户端的响应(例如,一个Angular拦截器)非常有用。
如果您希望中间件检查失败时错误响应被重定向,只需在您的wrappr.config中设置重定向路径即可
'redirect' => '/login'
当HTTP请求是Ajax请求时,此值将被忽略。
如何开发提供者
扩展Foothing\Wrappr\Providers\Permissions\AbstractProvider。
您需要实现强制性的check()方法,并且您可以选择实现或忽略其他可选方法。
/** * Check the given user has access to the given permission. * * @param $user * @param $permissions * @param null $resourceName * @param null $resourceId * * @return mixed */ public function check($user, $permissions, $resourceName = null, $resourceId = null); /** * Check the given subject has access to the given permission. * * @param $permissions * @param null $resourceName * @param null $resourceId * * @return mixed */ public function can($permissions, $resourceName = null, $resourceId = null); /** * Fluent method to work on users. * @param $user * @return self */ public function user($user); /** * Fluent method to work on roles. * @param $role * @return self */ public function role($role); /** * Return all permissions for the given subject. * @return mixed */ public function all(); /** * Grant the given permissions to the given subject. * * @param $permissions * @param null $resourceName * @param null $resourceId * * @return mixed */ public function grant($permissions, $resourceName = null, $resourceId = null); /** * Revoke the given permissions from the given subject. * * @param $permissions * @param null $resourceName * @param null $resourceId * * @return mixed */ public function revoke($permissions, $resourceName = null, $resourceId = null);