User Roles and Permissions in Laravel 5.8

User Roles and Permissions in Laravel 5.8

Thông thường trong các dự án của chúng ta làm, có những mối liên kết giữa các User và Roles,Permissions,Groups. Thông thường ta làm như vậy để kiểm tra quyền hạn của từng User, biết được họ đang ở vai trò nào? những quyền gì? Thuộc groups nào?
Nay mình sẽ đi tạo các mối liên hệ đó trong Laravel 5.8, bài này cũng khá dài, mình chỉ chia sẻ cách nhận biết và làm, còn lại mọi người có thể tự phát triển thêm theo ý mình!

Trong sơ đồ trên ta thấy rằng:
- User có nhiều Roles(vai trò), đồng thời Role có nhiều Users
- Một Role có nhiều Permissions(quyền)
- User có thể thuộc nhiều group khác nhau, một group thì có nhiều Users
- Trong 1 Group thì sẽ thuộc một Role(vai trò) nào đó

I.Cài đặt Laravel 5.8

# composer create-project --prefer-dist laravel/laravel laravel58 "5.8.*"

II.Tạo Migration in Laravel 5.8

- Table Users thì mặt định in Laravel đã có sẵn 
- Table Roles: # php artisan make:migration create_roles_table --create=roles

Schema::create('roles', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('name');
    $table->timestamps();
});

- Tạo liên kết giữa user và role: # php artisan make:migration create_user_role_table --create=user_role

Schema::create('user_role', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->unsignedBigInteger('user_id');
    $table->unsignedBigInteger('role_id');
    $table->foreign('user_id')->references('id')->on('users');
    $table->foreign('role_id')->references('id')->on('roles');
});

- Table groups :# php artisan make:migration create_groups_table --create=groups

Schema::create('groups', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('name');
    $table->unsignedBigInteger('role_id');
    $table->foreign('role_id')->references('id')->on('roles');
    $table->timestamps();
});

- Table Permissions:# php artisan make:migration create_permissions_table --create=permissions

Schema::create('permissions', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('name');
    $table->timestamps();
});

- Tạo liên kết giữa role và permission:# php artisan make:migration create_role_permission_table --create=role_permission

Schema::create('role_permission', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->unsignedBigInteger('role_id');
    $table->unsignedBigInteger('permission_id');
    $table->foreign('role_id')->references('id')->on('roles');
    $table->foreign('permission_id')->references('id')->on('permissions');
});

- Sau khi tạo xong bạn cần chạy câu lệnh để tạo table: php artisan migrate

III. Tạo Relationship Model (User,Role,Group,Permission) 

- Ta cần thiết lặp các mối liên kết khóa giữa các Table với nhau như sau:

* Model App\User.php

public function roles(){
    return $this->belongsToMany(Role::class,'user_role');
}

public function groups(){
    return $this->belongsToMany(Group::class,'user_group');
}

* Model App\Role.php 

public function users(){
    return $this->belongsToMany(User::class,'user_role');
}
public function permissions(){
    return $this->belongsToMany(Permission::class,'role_permission');
}
public function groups(){
    return $this->hasMany(Group::class);
}

* Model App\Group.php 

public function users(){
    return $this->belongsToMany(User::class,'user_group');
}
public function role(){
    return $this->belongsTo(Role::class);
}

* Model App\Permission.php

public function roles(){
    return $this->belongsToMany(Role::class,'role_permission');
}

IV.Tạo Auth in Laravel 5.8

- Ở đây mình dùng Auth in laravel để tạo đăng nhập và đăng ký thành viên cho đở tốn thời gian
# php artisan make:Auth 
- Mình lợi dụng thằng Auth này để tạo cấu trúc layout sẵn, cho đở tốn kém xiu thôi á mà::)
- Đầu tiên Register xong, thì sẽ chuyển qua Home, tại router('home') hồi mình sẽ show dữ liệu ra như thế này 

V. Tạo Controller in Laravel 5.8

- Chúng ta cần các Controller như bên dưới, ta cần sài Controller của model nào thì chỉ việc tạo chúng thôi.
+ HomeController.php ( đã có mặt định đi chạy php artisan make:Auth)

public function index()
{
    $users = User::with('roles','groups')->get();
    $roles = Role::with('users','permissions')->get();
    return view('home')->with(array('users'=>$users,'roles'=>$roles));
}

- Trong đoạn code trên mình gọi mối liên kết giữa User với Roles,Groups để lấy dữ liệu của chúng
- Sau đó mình return về View('home') để show dữ liệu ra như hình bên trên

+ UserController.php

public function index()
{
    $users = User::all();
    $roles = Role::all();
    return View('add_roles_user')->with(array('users'=>$users,'roles'=>$roles));
}
public function store(Request $request)
{
     $role = Role::find($request->role_id);
     $role->users()->detach($request->users);
     $role->users()->attach($request->users);
     return redirect()->route('home');
}

- Trong UserController.php mình chỉnh sửa lại hai function, function index() mình return về giao diện thêm add_role_user
- Còn function store(Request $request): dùng đề nhận dữ liệu từ form submit tới và xử lý thêm dữ liệu, ở đây mình cũng không có xét điều kiện gì hết, các bạn có thể xét điều kiện vào sau nhé

+ RoleController.php

public function index()
{
    $roles = Role::all();

    $permissions = Permission::all();
    return View('add_roles')->with(array('roles'=>$roles,'permissions'=>$permissions));
}
public function store(Request $request)
    {
       
        $role_id = $request->role_id;
        $role = Role::find($role_id);
        if(count($role)>0){
            $checkRole = Role::where('id',$role_id)->withCount('permissions')->get()->toArray();
            if($checkRole[0]['permissions_count']>0){
               $role->permissions()->detach();//delete all relationship in role_permission 
            }
            $role->permissions()->attach($request->permissions);//add list permissions
            return redirect()->route('home');
            
        }
        return redirect()->route('home');

    }

- Trong RoleController.php cũng có 2 function(index,store): 
+ Đầu tiên mình nhận dữ liệu từ form, kiểm tra xem cái role_id đó có trong dữ liệu không
+ Nếu có, mình tiếp tục kiểm tra dữ liệu trong mối liên kết bảng của(User & Role)->đó chính là table user_role trong database đó nhé, trong laravel có kèm theo một tính năng là trả về số dòng dữ liệu trong bảng của mối liên kết, dựa vào đó mà ta xử lý thôi.

VI. Tạo View Blade in Laravel 5.8

- Views/home.blade.php: mở file này lên và bạn chỉnh sửa lại như sau:

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <a href="{{route('role')}}" class="btn btn-success">Add Role</a>
            <a href="{{route('user')}}" class="btn btn-primary">Add User Role</a>
            <div class="card">
                <div class="card-header">Roles</div>
                <div class="card-body">
                    <table class="table">
                        <thead>
                            <tr>
                                <th>Roles</th>
                                <th>Permissions</th>
                                <th>User</th>
                            </tr>
                        </thead>
                        <tbody>
                        @foreach($roles as $role)
                            <tr>
                                <td>{{$role->name}}</td>
                                <td>
                                    @if(count($role->permissions)>0)
                                        @foreach($role->permissions as $permission)
                                             <span class="badge badge-success">{{$permission->name}}</span>
                                        @endforeach
                                    @else
                                        <span class="badge badge-danger">No permission</span>
                                    @endif
                                </td>
                                <td>
                                    <ul>
                                    @if(count($role->users)>0)
                                        @foreach($role->users as $user)
                                             <li class="badge badge-success">{{$user->name}}</li>
                                        @endforeach
                                    @else
                                        <li class="badge badge-danger">No user</li>
                                    @endif
                                    </ul>
                                </td>
                            </tr>
                        @endforeach
                        </tbody> 
                    </table>
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">Users</div>
                <div class="card-body">
                    <table class="table">
                        <thead>
                            <tr>
                                <th>Name</th>
                                <th>Role</th>
                                <th>Group</th>
                                <th>Edit</th>
                                <th>Delete</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach($users as $user)
                                
                                <tr>
                                    <td>{{$user->name}}</td>
                                    <td>
                                       
                                    @if(count($user->roles)>0)
                                        @foreach($user->roles as $role)
                                            <span class="badge  badge-success">{{$role->name}}</span>
                                        @endforeach
                                    @else
                                        <span class="badge badge-danger">No role</span>
                                    @endif  
                                    </td>
                                    <td>
                                    @if(count($user->groups)>0)
                                        @foreach($user->groups as $group)
                                           <span class="badge  badge-primary">{{$group->name}}</span>
                                        @endforeach
                                    @else
                                        <span class="badge badge-danger">No group</span>
                                    @endif
                                    </td>
                                    <td><a href="" class="badge badge-warning">Edit</a></td>
                                    <td><a href="" class="badge badge-danger">Delete</a></td>
                                </tr>

                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

- Tạo file Views/add_roles_user.blade.php

@extends('layouts.app')
@section('content')
<div class="container">
<form action="{{route('user.new')}}" method="post">
    <div class="row justify-content-center">
        <div class="col-md-6">
         @csrf
            <div class="card">
                <div class="card-header">Roles</div>
                <div class="card-body">
                  <select name="role_id" class="form-control">
                    @foreach($roles as $role)
                        <option value="{{$role->id}}">{{$role->name}}</option>
                    @endforeach
                   </select>
                </div>
                <div class="card-footer"><input type="submit" class="btn btn-success" name="add_role" value="Add Roles"/></div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">Users</div>
                <div class="card-body">
                   <ul>
                    @foreach($users as $user)
                        <li><input type="checkbox" name="users[]" value="{{$user->id}}">{{$user->name}}</li>
                    @endforeach
                   </ul>
                </div>
            </div>
        </div>
    </div>
</form>
</div>
@endsection

- Tạo Views/add_roles.blade.php 

@extends('layouts.app')
@section('content')
<div class="container">
<form action="{{route('role.new')}}" method="post">
    <div class="row justify-content-center">
        <div class="col-md-6">
         @csrf
            <div class="card">
                <div class="card-header">Roles</div>
                <div class="card-body">
                  <select name="role_id" class="form-control">
                    @foreach($roles as $role)
                        <option value="{{$role->id}}">{{$role->name}}</option>
                    @endforeach
                   </select>
                </div>
                <div class="card-footer"><input type="submit" class="btn btn-success" name="add_role" value="Add Roles"/></div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">Permissions</div>
                <div class="card-body">
                   <ul>
                    @foreach($permissions as $permission)
                        <li><input type="checkbox" name="permissions[]" value="{{$permission->id}}">{{$permission->name}}</li>
                    @endforeach
                   </ul>
                </div>
            </div>
        </div>
    </div>
</form>
</div>
@endsection

- Tiếp theo ta cần cấu hình file web.php, trong thư mục routers như sau:

Route::resource('user','UserController',[
    'names'=>[
        'index'=>'user',
        'store'=>'user.new',
    ]
]);
Route::resource('role','RoleController',[
    'names' => [
        'index' => 'role',
        'store' => 'role.new',
    
    ]
]);

Bài này có nhiều thứ còn chưa hoàn chỉnh! Mình chỉ mô tả để ta có thể hình dung mối liên kết giữa User & Roles và Permissions,Groups thôi. Có gì mọi người add vô thêm và tùy biến chúng như một món thức ăn ngon! ::)