I'm using Laravel 5.5.
I created 4 middlewares, one middleware by user role.
The admin has same rights as the employee. However, admin owns some more privileges.
Routing File:
Route::group(['prefix' => 'admin'], function() {
// EMPLOYEE AND ADMIN ROUTES
Route::group(['middleware' => ['admin', 'employe']], function() {
Route::get('showCreationSeance', 'AdministrationController#showCreationSeance');
Route::get('showAjoutCoach', 'AdministrationController#showAjoutCoach');
Route::get('showReservationClient', 'AdministrationController#showReservationClient');
Route::get('showAnnulationClient', 'AdministrationController#showAnnulationClient');
Route::post('creerSeance', 'AdministrationController#creerSeance')->name('admin/creerSeance');
Route::post('ajouterCoach', 'AdministrationController#ajouterCoach')->name('admin/ajouterCoach');
});
// ADMIN ROUTES
Route::group(['middleware' => 'admin'], function() {
Route::get('showCreationActivite', 'AdministrationController#showCreationActivite');
Route::get('showAjoutEmploye', 'AdministrationController#showAjoutEmploye');
Route::post('creerActivite', 'AdministrationController#creerActivite')->name('admin/creerActivite');
Route::post('ajouterEmploye', 'AdministrationController#ajouterEmploye')->name('admin/ajouterEmploye');
});
});
Middlewares:
class AdminMiddleware
{
public function handle($request, Closure $next)
{
$user = User::getUser(Auth::user()->id_utilisateur);
if(!$user->estAdmin()) {
throw new AuthorizationException();
}
return $next($request);
}
}
class EmployeMiddleware
{
public function handle($request, Closure $next)
{
$user = User::getUser(Auth::user()->id_utilisateur);
if(!$user->estEmploye()) {
throw new AuthorizationException();
}
return $next($request);
}
}
Methods used into middlewares:
public function estAdmin() {
$idStatutAdmin = Statut::select('id_statut')
->where('nom_statut', '=', 'ROLE_ADMIN')
->first();
return ($idStatutAdmin->id_statut == $this->id_statut) ? true : false;
}
public function estEmploye() {
$idStatutEmployee = Statut::select('id_statut')
->where('nom_statut', '=', 'ROLE_EMPLOYEE')
->first();
return ($idStatutEmployee->id_statut == $this->id_statut) ? true : false;
}
Stack Trace:
Illuminate\Foundation\Exceptions\Handler render
…/app/Exceptions/Handler.php 51
Illuminate\Auth\Access\AuthorizationException
…/app/Http/Middleware/AdminMiddleware.php 25
Illuminate\Foundation\Http\Kernel handle
…/public/index.php 55
The problem:
The routes defined for admin and employee didn't work and I get an error:
Symfony \ Component \ HttpKernel \ Exception \ AccessDeniedHttpException
No message
While routes for admin only work perfectly. Can you tell me if I'm doing this correctly?
When I'm connected as an admin, it is EmployeMiddleware which throw an error. And when I'm connected as employee, it is AdminMiddleware which throw an error.
Thank's for your help!
The user has the id_statut column which can only be ROLE_ADMIN or ROLE_EMPLOYEE. Take the following example:
$roles = [
'admin' => 2,
'employee' => 1
];
$user = [
'id_statut' => 1
];
if ($user['id_statut'] == $roles['employee']) {
// User is an employee - this code will execute
}
if ($user['id_statut'] == $roles['admin']) {
// User is not an admin - this code will NOT execute
}
if ($user['id_statut'] == $roles['employee'] && $user['id_statut'] == $roles['employee']) {
// User is an employee AND an admin
// This is impossible based on your database structure as id_statut cannot be both 1 and 2
}
An easy solution would be to check if the user is an employee or higher permission in estEmploye(). For example:
public function estEmploye() {
$idStatutEmployee = Statut::select('id_statut')
->where('nom_statut', 'IN', ['ROLE_EMPLOYEE', 'ROLE_ADMIN'])
->get('id_statut');
return in_array($this->id_status, $idStatutEmployee);
}
Related
I'm new with Laravel, and my web application consists of 3 types of users (guards): Admins, Agents, Players.
Authentication is working fine with Admins and Agents, since they shouldn't be able to see their dashboard unless they are logged in.
The problem with Players, which can access all the pages in the website as guests and when they login the only change is in the navigation bar.
I'm getting the following error:
Firefox has detected that the server is redirecting the request for this address in a way that will never complete.
RouteServiceProvider.php
public const HOME = '/';
public const LOGGEDIN = '/loggedin';
public const AGENT = '/agent';
public const ADMIN = '/admin';
web.php
Route::group(['namespace' => 'Front','middleware' => 'guest:player', 'middleware' => 'auth:player'], function(){
Route::get('/','FrontController#index')-> name('front.home');
Route::get('loggedin','FrontController#index')-> name('front.loggedin');
Route::get('Page1','FrontController#get_page1')-> name('front.page1');
Route::get('Page2','FrontController#get_page2')-> name('front.page2');
Route::get('logout','FrontController#logout')-> name('front.logout');
});
Authenticate.php
protected function redirectTo($request)
{
$current_req = request()->segment(count(request()->segments()));
if($current_req == 'admin'){
return route('admin.login');
}
elseif($current_req == 'agent'){
return route('agent.login');
}
elseif($current_req == ''){
return route('front.home');
}
else{
return route('front.home');
}
}}
RedirectIfAuthenticated.php
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
if($guard == 'agent')
return redirect(RouteServiceProvider::AGENT);
elseif($guard == 'admin')
return redirect(RouteServiceProvider::ADMIN);
elseif($guard == 'player'){
return redirect(RouteServiceProvider::LOGGEDIN);
}
else
return redirect(RouteServiceProvider::HOME);
}
return $next($request);
}
I want show domen url user id after signin, example domen/specialist/id.
ALREADY AS DAY 2 IT IS NOT RECEIVED TO DO. Maybe I'm doing something wrong help please.
This my web.php code
// Front End Routes
Route::group([
'namespace' => 'landing',
'middleware' => 'groups',
], function (){
Route::get('/', 'PagesController#index')->name('landing.index');
Route::get('/specialist/{id}', 'SpecialistDashboardController#dashboard')-
>name('frontend.specialist.dashboard');
Route::get('/logout', '\App\Http\Controllers\Auth\LoginController#logout');
});
Specialist Dashboard Controller code
class SpecialistDashboardController extends Controller
{
public function dashboard($id){
$id = Auth::user()->id;
return view('Frontend.specialists.dashboard.index');
}
public function profile_settings(){
return view('Frontend.specialists.profile_settings.index');
}
}
GroupsMiddleware
public function handle($request, Closure $next)
{
// ADMIN = 5
if (\Auth::check() && Auth::user()->groups == 5){
return $next($request);
}
// PATIENTS = 1
elseif(\Auth::check() && Auth::user()->groups == 1){
return redirect()->route('landing.index');
}
// SPECIALISTS = 3
elseif (\Auth::check() && Auth::user()->groups == 3){
return redirect()->route('frontend.specialist.dashboard');
}
}
Error message:
Missing required parameters for [Route: frontend.specialist.dashboard] [URI: specialist/{id}].
Your frontend.specialist.dashboard route requires a id paramter but you didn't provide any when redirecting. Also looking at your SpecialistDashboardController, the $id can be omitted since you're overwriting it with Auth::id().
Try doing this:
# remove the {id} param
Route::get('/specialist', 'SpecialistDashboardController#dashboard')-
>name('frontend.specialist.dashboard');
class SpecialistDashboardController extends Controller
{
...
public function dashboard(){ // remove the $id param
$id = Auth::user()->id;
return view('Frontend.specialists.dashboard.index');
}
...
}
But if in any case you need the id param, you can provide the value for it in redirect by doing
return redirect()->route('frontend.specialist.dashboard', ['id' => $id]);
I have a signup route. After it register on step1, it emails to the user to verify his account and have a link on his email. After clicking the link, it should redirect to signup/step2, and finished and he can access the job-seeker/home.
so the logic is after finished the registration, user cannot visit again to signup/step2 cause user already finished fill up the form.
and before fillup signup/step2, he can't access also the job-seeker/home. So it's vice versa.
basically my middleware was first: check if the user completed the step2 and added true on column is_completed in database. then on the second middleware is to visit only his route by his role, he can't access other routes from other role and redirect to his home based on his role.
But it throws me too many redirect and switching both side even I still didn't fill up the step2 yet. this is my gif below.
MyCode
Kernel.php
class Kernel extends HttpKernel
{
...
protected $routeMiddleware = [
...
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'isCompleted' => \App\Http\Middleware\IsCompleted::class,
];
Middleware/IsCompleted.php
class IsCompleted
{
public function handle($request, Closure $next)
{
if(auth()->user()->isCompleted == 1){
return $next($request);
}
// if 0, redirect to step2
return redirect()->route('register.step2');
}
Middleware/RedirectIfAuthenticated.php
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
if ( Auth::user()->hasRole('job-seeker') ) {
return redirect()->route('job-seeker.home');
} else if(Auth::user()->hasRole('admin')) {
return redirect()->route('admin.home');
}
}
return $next($request);
Routes/Web.php
<?php
Route::get('/', function () {
return view('welcome');
});
Route::group(['middleware' => ['verified', 'isCompleted']], function() {
Route::group(['prefix' => 'admin', 'name' => 'admin.'], function() {
Route::get('/home', function(){ return "test"; })->name('admin.home');
});
Route::group(['prefix' => 'job-seeker', 'name' => 'job-seeker.'], function() {
Route::get('/home', 'Jobseeker\HomeController#index')->name('job-seeker.home');
});
});
Auth::routes(['verify' => true, 'register' => false]);
Route::get('signup/{usertype}' , 'Auth\RegisterController#getStep1')->name('register.step1');
Route::post('signup/{usertype}' , 'Auth\RegisterController#postStep1');
Route::group(['middleware' => ['auth']], function() {
Route::get('signup/step2' , 'Auth\RegisterController#getStep2')->name('register.step2');
Route::post('signup/step2' , 'Auth\RegisterController#postStep2');
});
EDIT 1
I inspect the page and go to network tab, and this is the result.
your RedirectIfAuthenticated keeps redirecting all the time. It doesn't ever get to $next($request) for Authenticated User.
You need to have some logic like
if (route is seeker.home and user can visit seeker.home) {
return $next(request);
}
instead of
return redirect()->route('job-seeker.home');
I am trying to implement 3 user types in to my application, I am using the default Auth of Laravel.
I created 2 extra middlewares to acheive the to extra user(admin & Districtlogin) conditions along with user approval middleware, and using the default for laravel user
Admin middleware
class Admin
{
tion handle($request, Closure $next)
{
if( Auth::check() && Auth::user()->isAdmin == 1)
{
return $next($request);
}
Auth::logout();
return redirect('login')->with('error','You have not admin access');
}
}
Districtlogin Middleware
class Districtlogin
{
public function handle($request, Closure $next)
{
if (Auth::check() && Auth::user()->isAdmin == 2) {
return $next($request);
}
Auth::logout();
return redirect('login')->with('error', 'You have not admin access');
}
}
One additional middleware to check if the user is approved
class ApproveUser
{
public function handle($request, Closure $next)
{
if( Auth::check() && Auth::user()->row_status == 1)
{
return $next($request);
}
return redirect('/userapprove');
}
I am able to redirect them based on the login
Auth/LoginController
public function redirectPath()
{
if (Auth::user()->isAdmin == 1 && Auth::user()->row_status == 1) {
return '/adminindex';
} elseif (Auth::user()->row_status == 0) {
return '/userapprove';
} elseif (Auth::user()->isAdmin == 2 && Auth::user()->row_status == 1) {
return '/districtindex';
}
return '/engineerdashboard';
}
Here is my
kernel.php
entry
'admin' => \App\Http\Middleware\Admin::class,
'districtlogin' => \App\Http\Middleware\Districtlogin::class,
'userapprove' => \App\Http\Middleware\ApproveUser::class,
I would like to group the admin and Districtlogin middleware.
I am using CRUD, I would like Districtlogin to have access to few controllers - index,store,update
When I try to group the middleware, I am redirected back to the login screen. Neither of the middleware works
Here's what I tried,
1)
Route::middleware(['admin'])->group(function () {
//Admin Dashboard
Route::resource('adminindex', 'AdminindexController')->middleware('districtlogin');
Route::get('adminindex/new', 'AdminindexController#admindashboard');
});
2)
Route::middleware(['admin','districtlogin'])->group(function () {
//Admin Dashboard
Route::resource('adminindex', 'AdminindexController');
Route::get('adminindex/new', 'AdminindexController#admindashboard');
});
3)
Route::middleware(['admin',''])->group(function () {
//Admin Dashboard
Route::resource('adminindex', 'AdminindexController');
Route::get('adminindex/new', 'AdminindexController#admindashboard');
Route::middleware(['districtlogin'])->group(function () {
Route::resource('adminindex', 'AdminindexController');
});
});
But when I use the 'OR' condition, I am able to access the pages
Route::group(['middleware' => ['admin' OR 'districtlogin']], function () {
//Admin Dashboard
Route::resource('adminindex', 'AdminindexController');
Route::get('adminindex/new', 'AdminindexController#admindashboard');
});
The controllers are accessible by both the middlewares. But how do I limit the Crud functions based on the middleware.
I am completely clueless on how to achieve it.
The complete answer is:
The two middlewares are incompatible with each other, they have no common ground. Where one succeeds the other fails and redirects to login page.
So this explains the first part of your question.
The second part is that Route::group(['middleware' => ['admin' OR 'districtlogin']] .. is meaningless as regards to configuring middleware. it is equivalent to Route::group(['middleware' => ['admin']].. since the expression 'admin' OR 'districtlogin' always evaluates to first operand. Plus it is misleading as Laravel does not support having middlewares one or the other it is meaningless expression.
The solution:
Either use one middleware that can support both options, for example:
class AdminOrDistrictlogin
{
public function handle($request, Closure $next)
{
if (Auth::check() && Auth::user()->isAdmin >= 1 ) {
return $next($request);
}
Auth::logout();
return redirect('login')->with('error', 'You have not admin access');
}
}
entry:
'adminOrdistrict' => \App\Http\Middleware\AdminOrDistrictlogin::class,
'userapprove' => \App\Http\Middleware\ApproveUser::class,
routes:
Route::middleware(['adminOrdistrict'])->group(function () {
//Admin or District Dashboard, distignuish later in your code
Route::resource('adminindex', 'AdminindexController');
Route::get('adminindex/new', 'AdminindexController#admindashboard');
});
And in your controllers and views refine further by checking Auth::user()->isAdmin value for distinguishing between simple admins or districts
Or, if the functionality is very different between simple admins and districts, create new and different routes for admin and district and use each middleware in the appropriate route group for each type of user.
For example:
Route::middleware(['admin'])->group(function () {
//Admin Dashboard
Route::resource('adminindex', 'AdminindexController');
Route::get('adminindex/new', 'AdminindexController#admindashboard');
});
Route::middleware(['districtlogin'])->group(function () {
//District Dashboard
Route::resource('districtindex', 'DistrictindexController');
Route::get('districtindex/new', 'DistrictindexController#admindashboard');
});
Choice is yours :)
I have Route group with middleware (I use Zizaco/entrust package):
Route::group(['as' => 'admin.', 'prefix' => 'admin', 'middleware' => ['role:admin']], function (){
...
});
When I try to enter http://mysite/admin while not authenticated I get exception
Symfony \ Component \ HttpKernel \ Exception \ HttpException
No message
But I want to return 403.
I tried to do this:
Route::fallback(function(){
abort(403);
});
but it didn't helped.
Edit 1: here we have exception handle in Laravel 5.5.28
public function abort($code, $message = '', array $headers = [])
{
if ($code == 404) {
throw new NotFoundHttpException($message);
}
throw new HttpException($code, $message, null, $headers);
}
As you can see, there is no 403 handle.
you have to modify handle method of role middleware
public function handle($request, Closure $next, $roles)
{
if (!is_array($roles)) {
$roles = explode(self::DELIMITER, $roles);
}
if ($this->auth->guest() || !$request->user()->hasRole($roles)) {
abort(403); // notice here it returns 403
}
return $next($request);
}