[英]Laravel 5.1 users, roles and actions
I am creating an application using Laravel 5.1 with users , roles and actions . 我正在使用Laravel 5.1创建一个包含用户 , 角色和操作的应用程序。
The table setup is like so: 表格设置如下:
user 用户
id name
1 John Smith
2 Fred Smith
role 角色
id name
1 Administrator
2 Customer
role_user ROLE_USER
user_id role_id
1 1
2 1
action 行动
id name description path
1 dashboard ability to access dashboard /admin
2 editAdmin ability to edit admins /admin/users/administrators/{id}/edit
action_role action_role
action_id role_id
1 1
2 1
The user
table holds ALL users on the site, including administrators and customers. user
表包含站点上的所有用户,包括管理员和客户。
The role
table holds all the possible roles a user can have. role
表包含用户可以拥有的所有可能角色。 For example Administrator or Customer . 例如管理员或客户 。
The role_user
table is a pivot table which links role
to user
. role_user
表是一个将role
与user
链接的数据透视表。
The action
table lists all of the actions possible (ie urls or routes) on the app. action
表列出了应用程序上可能的所有操作(即URL或路由)。
The action_role
is a pivot table which links action
to role
. action_role
是一个数据透视表,用于将action
与role
。
So to summarise: 总结一下:
I want to have a middleware setup which checks on page load if the user has permissions to view the current page. 我想要一个中间件设置,如果用户有权查看当前页面,它会检查页面加载。 In order to do this, I need to be able to access a users actions, using a call like this:
为了做到这一点,我需要能够使用如下调用来访问用户操作:
$user->roles()->actions();
How do I setup my eloquent relationships to support this kind of call? 如何设置我雄辩的关系来支持这种呼叫?
UPDATE UPDATE
My relationships are setup like so in my models: 我的关系在我的模型中设置如下:
User 用户
/**
* The roles that belong to the user.
*
* @return Object
*/
public function roles()
{
return $this->belongsToMany('App\Models\User\Role')->withTimestamps();
}
Role 角色
/**
* The actions that belong to the role.
*
* @return Object
*/
public function actions()
{
return $this->belongsToMany('App\Models\User\Action');
}
/**
* The users that belong to the role.
*
* @return Object
*/
public function users()
{
return $this->belongsToMany('App\Models\User\User');
}
Action 行动
/**
* The roles that belong to the action.
*
* @return Object
*/
public function roles()
{
return $this->belongsToMany('App\Models\User\Role');
}
Eloquent does not have a HasManyThrough
relationship across 2 pivot tables. HasManyThrough
在两个数据透视表中没有HasManyThrough
关系。
1. You can get the actions by lazy eager loading the roles and actions, then extracting them: 1.您可以通过懒惰的加载角色和操作来获取操作,然后提取它们:
$actions = $user->load('roles.actions')->roles->pluck('actions')->collapse()->unique();
2. You can check the action directly in the database, using a whereHas
constraint: 2.您可以使用
whereHas
约束直接在数据库中检查操作:
$allowed = $user->roles()->whereHas('actions', function ($query) use ($action) {
$query->where('name', $action);
})->exists();
For handling user, user roles and user permissions you can simply use Toddish package. 要处理用户,用户角色和用户权限,您只需使用Toddish包。
There are lot of things this package does for you. 这个包有很多东西给你。 like:
喜欢:
$user->is('Your Defined Role');
$user->can('add_user');
$user->level(7);
For installation just read it's documentation. 如需安装,请阅读它的文档。
Although you have mentioned that your Eloquent models (and their relationships) are set up, I am assuming that you have the following in your application already: 虽然您已经提到您的Eloquent模型(及其关系)已经设置,但我假设您的应用程序中已经有以下内容:
User model 用户模型
class User extends Eloquent {
public function roles() {
return $this->belongsToMany('App\Models\Role');
}
}
Role model 榜样
class Role extends Eloquent {
public function actions() {
return $this->belongsToMany('App\Models\Action');
}
public function users() {
return $this->belongsToMany('App\Models\User');
}
}
Action model 行动模型
class Action extends Eloquent{
public function roles(){
return $this->belongsToMany('App\Models\Role');
}
}
Given the above set properly, you can't certainly make a call like the following as Laravel will assume you're making a call to a Query Builder method or whatever [which in fact doesn't exist]: 鉴于以上设置正确,您无法像下面那样进行调用,因为Laravel会假设您正在调用Query Builder方法或其他任何[实际上不存在]:
$userActions = App\Models\User::find(1)->roles()->actions();
Instead, you have to use Laravel's magical whereHas
method to query relations where multiple nested relations are involved. 相反,您必须使用Laravel的神奇
whereHas
方法来查询涉及多个嵌套关系的关系。
Now, having the user's id
and the current allowed action
[ which indeed can be utilized in your middleware ], it can be determined whether the user is allowed to see the page: 现在,拥有用户的
id
和当前允许的action
[ 确实可以在中间件中使用 ],可以确定是否允许用户查看页面:
$hasAccess = App\Models\User::whereHas('roles.actions', function($q) use ($id, $action){
$q->where('users.id', $id);
$q->where('actions.name', $action);
})->get()->toArray();
if($hasAccess){ // or `count($hasAccess) > 0`. The former will work since any number > 0 evaluates to true in PHP
//user has access
}
Notice the nesting of relationships with .
注意与之关系的嵌套
.
. 。
In Laravel the existence of a relationship between models is determined with has
and whereHas
methods. 在Laravel中,模型之间存在关系是用
has
和whereHas
方法确定的。 The has
method is used to only determine if a relationship exists , eg by executing App\\User::has('roles')->get()
you'll always get a list/collection of users which at least have any roles . has
方法用于仅确定是否存在关系 ,例如通过执行App\\User::has('roles')->get()
您将始终获得至少具有任何角色的用户列表/集合。 More power to this can be added with whereHas
with which you can add where
clauses to the actual query. 可以使用
whereHas
添加更多功能,您可以在where
添加实际查询的子句。
Hi this is how I solved this. 嗨这就是我解决这个问题的方法。
I didn't use an actions table. 我没有使用动作表。 Just users , roles and the user_role table.
只是用户 , 角色和user_role表。 After the solution, I pass my custom middleware a role array to every route I create like:
解决方案之后,我将自定义中间件的角色数组传递给我创建的每条路径:
Route::get('insights',[
'as'=>'insights',
**'middleware'=>['access.level'],**
**'roles'=>['admin','customer'],**
'uses'=>'CustomersController@index'
]);
Files modified: app\\Http\\Controllers\\Controller.php Custom middleware: CheckAccessLevel app\\Http\\Kernel.php app\\Http\\routes.php 修改的文件:app \\ Http \\ Controllers \\ Controller.php 自定义中间件: CheckAccessLevel app \\ Http \\ Kernel.php app \\ Http \\ routes.php
Controller.php In this file, I wanted to eager load the current logged in user with his roles and make it a global variable in all views as {{currentUser}} and in all my controllers as "$this->currentUser" . Controller.php在这个文件中,我想用他的角色急切加载当前登录的用户,并在所有视图中将其作为全局变量{{currentUser}},并在所有控制器中将其设置为“$ this-> currentUser” 。 this is the code:
这是代码:
protected $currentUser;
public function __construct() {
if(isset(Auth::user()->username)){
$this->currentUser = User::with('roles')->where(['username' => Auth::user()->username])->first();
// Share this property with all the views and controllers in your application.
view()->share('currentUser', $this->currentUser);
}
}
Custom Middleware: CheckAccessLevel.php 自定义中间件: CheckAccessLevel.php
Over here in the middleware, I retrieve the roles array passed to the route and and also the roles assigned to the current user. 在中间件中,我检索传递给路由的角色数组以及分配给当前用户的角色。 After i get these variables, I intersect them to see if there is a match before I pass the user on.
在我得到这些变量之后,我将它们相交以查看是否存在匹配,然后再将用户打开。 check the code below:
检查以下代码:
//if user is not logged in, show them where to login :)
if (!Auth::check()) {
return redirect()->route('user::login');
}
//Otherwise get the roles for that route
$get_route_action = $request->route()->getAction();
$get_route_roles = $get_route_action['roles'];
//Eager load the user with their list of roles
$eager_user = User::with('roles')->where(['id'=>$request->user()->id])->first();
$user_roles = $eager_user->roles->pluck('role_name')->toArray();
//intersect the users roles with the route roles to see if there is a match
foreach ($user_roles as $user_role){
if(in_array($user_role, $get_route_roles)){
return $next($request);
}
}
Kernel.php over here, i register my route as "access.level" inside the route middleware group Kernel.php在这里,我在路由中间件组中注册了我的路由“access.level”
Route.php then whenever I create a route, I just pass in the allowed role names to it and voala! Route.php然后每当我创建一个路由时,我只是将允许的角色名称传递给它和voala! It works for me..
这个对我有用..
I hope this helps. 我希望这有帮助。
You need a HasManyThrough relationship here.. Here's something to get you started. 你需要一个HasManyThrough关系..这是让你入门的东西。
Judging by your given tables I see it has a one-to-many relationship with user and roles. 根据您给定的表格判断,我发现它与用户和角色有一对多的关系。 While action and roles also has many-to-many relationship.
虽然行动和角色也有多对多的关系。
But first you need to create models for each entities(user,role,action) to follow the MVC structure. 但首先,您需要为每个实体(用户,角色,操作)创建模型以遵循MVC结构。 You could easily make these models from the command line using the Laravel's artisan with this command.
您可以使用Laravel的工匠使用此命令从命令行轻松制作这些模型。
php artisan make:model User
Make sure to also add or change columns in the newly created migrations. 确保还在新创建的迁移中添加或更改列。 Assuming you also have your pivot tables set up for the 3 tables, you can now add the relationships.
假设您还为3个表设置了数据透视表,现在可以添加关系。
class User extends Model {
//
protected $table = 'users';
/*
* @var table
*
*/
public function action()
{
return $this->hasManyThrough('App\Action', 'App\Role');
}
}
Now you have a HasManyThrough relationship. 现在你有一个HasManyThrough关系。 you can query like this directly no need to include role.
您可以直接查询,不需要包含角色。
//this
$actions = User::find(1)->action();
//instead of
$actions = User::find(1)->role()->action();
//this will return all actions available to a user with id of 1
NOTE I also suggest you make your role and user models to be on a one to one relationship. 注意我还建议您将角色和用户模型建立在一对一的关系中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.