cartalyst / sentinel

A framework agnostic authentication & authorization system.
BSD 3-Clause "New" or "Revised" License
1.51k stars 238 forks source link

[Proposal] New method: User()->inAnyRole() #440

Closed felipemarques closed 5 years ago

felipemarques commented 6 years ago

Hello guys,

Recently, i needed to create a custom method for check multiple roles of an user, using a middleware. I could do this implementing an foreach an other workarounds, but, if i had a specific method like this, i could minimize my work. So, in the below my middleware code, and my method inAnyRole() implemented on the Eloquent user model:

User::class

<?php

namespace Modules\User\Entities;

use App\Models\AppModelTrait;
use Cartalyst\Sentinel\Roles\RoleInterface;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Foundation\Auth\Access\Authorizable;
use App\Models\AppModel;

/**
 * Class User
 * @package Modules\User\Entities
 */
class User extends \Cartalyst\Sentinel\Users\EloquentUser implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword;
    use AppModelTrait;

    /**
     * Validation rules
     * @var array
     */
    protected static $rules = [
        'default' => [
            'email'                     => 'required|max:255',
            'name'                      => 'required|min:4',
            'first_name'                => 'sometimes|max:255',
            'last_name'                 => 'sometimes|max:255',
            'is_show_welcome_video'     => 'sometimes|boolean',
        ],
        'update' => [
            'email'                     => 'required|max:255',
            'name'                      => 'required|max:255',
            'first_name'                => 'required|max:255',
            'last_name'                 => 'required|max:255',
            'is_show_welcome_video'     => 'sometimes|boolean',
        ],
    ];

    /**
     * @var array
     */
    protected static $messages = [];

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'avatar',
        'email',
        'password',
        'first_name',
        'last_name',
        'company_id',
        'permissions',
        'api_token',
        'company_id',
        'is_show_welcome_video',
    ];

    /**
     * @var array
     */
    protected $dates = [
        'last_login'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be casted to native types.
     *
     * @var array
     */
    protected $casts = [
        'is_show_welcome_video'     => 'boolean',
    ];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     * @alias usersMeta
     */
    public function meta()
    {
        return $this->hasMany(\Modules\User\Entities\UserMeta::class);
    }

    /**
     * @param $role
     * @return bool
     */
    public function inAnyRole($role)
    {
        if (is_array($role) && !empty($role)) {

            $roles = $role;

            foreach ($roles as $role) {

                if ($role instanceof RoleInterface) {
                    $roleId = $role->getRoleId();
                }

                foreach ($this->roles as $instance) {
                    if ($role instanceof RoleInterface) {
                        if ($instance->getRoleId() === $roleId) {
                            return true;
                        }
                    } else {
                        if ($instance->getRoleId() == $role || $instance->getRoleSlug() == $role) {
                            return true;
                        }
                    }
                }

            }

        } else {

            if ($role instanceof RoleInterface) {
                $roleId = $role->getRoleId();
            }

            foreach ($this->roles as $instance) {
                if ($role instanceof RoleInterface) {
                    if ($instance->getRoleId() === $roleId) {
                        return true;
                    }
                } else {
                    if ($instance->getRoleId() == $role || $instance->getRoleSlug() == $role) {
                        return true;
                    }
                }
            }

        }

        return false;
    }
}

RoleAuthorizationCheckMiddleware::class

<?php namespace Modules\User\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

/**
 * Class RoleAuthorizationCheckMiddleware
 * @package Modules\User\Http\Middleware
 */
class RoleAuthorizationCheckMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next, ...$role)
    {

        // iam using Sentinel module
        $user = $request->user();

        if ($user->inAnyRole($role)) {
            return $next($request);
        } else {
            return redirect(route('dashboard.home'))->withErrors(['status' => trans('Only users with permission can access this feature.']));
        }
    }
}
brunogaspar commented 5 years ago

Looks nice.

Want to send a pull request with the implementation + a test or two?

brunogaspar commented 5 years ago

Closing due to lack of activity. Feel free to reopen if you still have issues or other questions.