Простой подход защиты маршрута на основе ролей Laravel 5.2

Я хочу защитить свои маршруты на основе ролей.
Это то, что я сделал, но я не могу заставить его работать.

Ролевая модель:

protected $table = 'roles';

protected $fillable = array(
'name', 'description'
);

public function users(){
return $this->belongsToMany('App\User', 'user_role', 'role_id', 'user_id');
}

Роль миграции

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

Файл RoletableSeeder

Role::create([
'id'            => 1,
'name'          => 'Admin',
'description'   => 'Admin User.'
]);
Role::create([
'id'            => 2,
'name'          => 'Vendor',
'description'   => 'Vendor User.'
]);
Role::create([
'id'            => 3,
'name'          => 'User',
'description'   => 'Simple User.'
]);

Примерный маршрут:

Route::get('/admin/dashboard', [
'uses' => 'AdminController@adminDashboard',
'as' => 'admin.dashboard',
'middleware' => ['auth', 'roles'],
'roles' => ['Admin']
]);

Модель пользователя:

protected $fillable = [
'email','username', 'password', 'confirmation_code'
];

protected $hidden = [
'password', 'remember_token',
];

public function orders() {
return $this->hasMany('App\Order');
}

public function roles(){
return $this->belongsToMany('App\Role', 'user_role', 'user_id', 'role_id');
}

public function hasRole($roles){
$this->have_role = $this->getUserRole();

if($this->have_role->name == 'Admin') {
return true;
}
if(is_array($roles)){
foreach($roles as $need_role){
if($this->checkIfUserHasRole($need_role)) {
return true;
}
}
} else{
return $this->checkIfUserHasRole($roles);
}
return false;
}
private function getUserRole(){
return $this->roles()->getResults();
}
private function checkIfUserHasRole($need_role){
return (strtolower($need_role)==strtolower($this->have_role->name)) ? true : false;
}

Файл CheckRole.php, который находится внутри промежуточного программного обеспечения:

<?php namespace App\Http\Middleware;
use Closure;
class CheckRole{

public function handle($request, Closure $next)
{

$roles = $this->getRequiredRoleForRoute($request->route());
if($request->user()->hasRole($roles) || !$roles){
return $next($request);
}
return response([
'error' => [
'code' => 'INSUFFICIENT_ROLE',
'description' => 'You are not authorized to access this resource.'
]
], 401);
}
private function getRequiredRoleForRoute($route)
{
$actions = $route->getAction();
return isset($actions['roles']) ? $actions['roles'] : null;
}
}

и наконец я добавил одну строку в ядро:

protected $routeMiddleware = [
...
'roles'         => 'App\Http\Middleware\CheckRole',
];

У кого-нибудь есть идеи? Или лучший / более простой способ сделать это? Заранее спасибо!

2

Решение

Это было мое решение, и я не говорю, что это лучшая практика, и она не лучше вашей.

я создал это промежуточное ПО:

<?php

namespace App\Http\Middleware;

use Closure;

class MustHaveRole
{
/**
* Handle an incoming request.
*
* @param  \Illuminate\Http\Request  $request
* @param  \Closure  $next
* @return mixed
*/
public function handle($request, Closure $next, $role)
{

if(auth()->check() && auth()->user()->active && (auth()->user()->hasRole($role) || auth()->user()->hasRole('admin')) ){

return $next($request);

} else {
abort(403);
}
}
}

внутри app / Http / Kernel.php добавлена ​​последняя строка:

protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'role' => \App\Http\Middleware\MustHaveRole::class,
];

и внутри пользовательской модели создано 2 метода:

// define connection with roles table
public function roles()
{
return $this->belongsToMany(Role::class);
}

// check if user has that $role
public function hasRole($role)
{
return $this->roles->contains('name', $role);
}

и у меня есть модель под названием Роль:

<?php

namespace App;

use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;

class Role extends Model
{

use SoftDeletes;

public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
}

и сеялка для этой таблицы:

<?php

use Illuminate\Database\Seeder;

class RolesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// check if table roles is empty
if(DB::table('roles')->get()->count() == 0){

// multiple insertion
DB::table('roles')->insert([
['name' => 'admin'],
['name' => 'agency'],
['name' => 'endcustomer'],
]);

} else { echo "\e[31mTable is not empty, therefore NOT "; }

}
}

и теперь внутри моего конструктора контроллера я могу вызвать это промежуточное ПО:

class ItemsController extends Controller
{

public function __construct() {
$this->middleware('auth');
$this->middleware('role:endcustomer');
}

...

Все это делается без каких-либо дополнительных пакетов … просто простой … если у вас есть еще вопросы, не стесняйтесь задавать.

2

Другие решения

Ну, это то, что я сделал и на самом деле работал.

RoleTableSeeder, Role migration, Role model и реестр промежуточного программного обеспечения остается таким же, как исходный пост.

В CheckRole.php:

<?php
namespace App\Http\Middleware;
use Closure;

class CheckRole{

public function handle($request, Closure $next){
if ($request->user()=== null) //for guests
return redirect()->route('product.index');

$actions = $request->route()->getAction();
$roles = isset($actions['roles']) ? $actions['roles'] : null;

if ($request->user()->hasAnyRole($roles) || !$roles)
return $next($request);
return redirect()->route('product.index'); //for unauthorized users
}
}

В User model: (отношения точно такие, как в оригинальном посте)

public function hasAnyRole($roles){
if (is_array($roles)){
foreach ($roles as $role) {
if ($this->hasRole($role)) {
return true;
}
}
} else if ($this->hasRole($roles)) {
return true;
}
return false;
}

public function hasRole($role){
if ($this->roles()->where('name', $role)->first()){
return true;
}
return false;
}

И пример маршрута:

Route::get('...', [
...
'middleware' => 'roles',
'roles' => 'Admin' //or whatever you have in `RolesTableSeeder` in name column
]);
0

По вопросам рекламы [email protected]