I have made a Laravel 8 application (link to GitHub repo) that requires user registration and login.
I am currently working on adding user roles and permissions. I have 3 roles (types of users): Admin, Author, and Member. Each type of user should have access to a section of the dashboard.
The users table:
The roles table:
In routes\web.php
I have:
Route::get('/', [HomepageController::class, 'index'])->name('homepage');
Auth::routes();
Route::group(['middleware' => ['auth']], function() {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
Route::get('/dashboard/profile', [UserProfileController::class, 'index'])->name('profile');
Route::match(['get', 'post'],'/dashboard/profile/update', [UserProfileController::class, 'update'])->name('profile.update');
Route::post('/dashboard/profile/deleteavatar/{id}/{fileName}', [UserProfileController::class, 'deleteavatar'])->name('profile.deleteavatar');
//User roles
Route::get('/dashboard/author', [AuthorController::class, 'index']);
});
In the User model (app\Models\User.php
) I have:
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'role_id',
'username',
'first_name',
'last_name',
'email',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function roles() {
return $this->belongsToMany(Role::class);
}
public function users()
{
return $this
->belongsToMany('App\User');
}
public function authorizeRoles($roles)
{
if ($this->hasAnyRole($roles)) {
return true;
}
abort(401, 'This action is unauthorized.');
}
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;
}
}
In the AuthorController (Controllers\Dashboard\AuthorController.php)
class AuthorController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware('role:ROLE_Author');
}
public function index()
{
return view('dasboard.author');
}
}
As the CheckRole middleware shows, if the user is not authorised, the message should be "This action is unauthorized":
class CheckRole
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next, $role)
{
if (!$request->user()->hasRole($role)) {
abort(401, 'This action is unauthorized.');
}
return $next($request);
}
}
The problem
For a reason I have not been able to find out, trying to redirect an author to it's section of the admin panel results in a 403 error:
User does not have any of the necessary access rights.
Question
What am I doing wrong?