2016-12-25 105 views
2

我想根據角色保護我的路線。 這就是我所做的,但我似乎無法得到它的工作。基於角色的路線保護的簡單方法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' => '[email protected]', 
'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); 
     } 
    } 
} 

內部應用程序/ 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'); 
    } 

... 

這一切都是沒有任何附加軟件包完成...只是平原laravel ...如果你有任何問題隨時問。

+0

謝謝您回答隊友。我會看看! – daino92

+0

你看看嗎?如果有幫助,請接受答案 – lewis4u

+0

抱歉不能早日回覆。我發現了另一個解決方案,我的問題,工作得很好。無論如何感謝你的努力。 – daino92

0

那麼這就是我所做的和實際工作。

RoleTableSeederRole 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 
]);