基于角色Laravel 5.2的简单路径保护方法

时间:2016-12-25 14:28:21

标签: php laravel routes roles protection

我想根据角色保护我的路线。 这就是我所做的,但我似乎无法让它发挥作用。

角色模型:

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 个答案:

答案 0 :(得分: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);
}

我有一个名为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 "; }

    }
}

现在在我的Controller构造函数中,我可以调用该中间件:

class ItemsController extends Controller
{

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

...

这一切都是在没有任何额外套餐的情况下完成的......只是简单的laravel ......如果您有任何其他问题可以随意提问。

答案 1 :(得分:0)

这就是我所做的和实际工作。

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