简体   繁体   English

Laravel 5.1用户,角色和操作

[英]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表是一个将roleuser链接的数据透视表。

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是一个数据透视表,用于将actionrole

So to summarise: 总结一下:

  • Users have roles 用户有角色
  • Roles have actions 角色有行动
  • A user can have many roles 用户可以拥有许多角色
  • A role can have many actions 角色可以有很多动作

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 . 注意与之关系的嵌套 . .


Relationship Existence in Laravel : Laravel中的关系存在

In Laravel the existence of a relationship between models is determined with has and whereHas methods. 在Laravel中,模型之间存在关系是用haswhereHas方法确定的。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM