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 :)
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 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'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);
}
I am using laravel 4 and here is my AdminController file :
class AdminController extends BaseController {
protected $layout = "admin.layout";
public function __construct() {
// security for the forms and access
$this->beforeFilter('csrf', array('on'=>'post'));
$this->beforeFilter('auth.admin' , array('except' =>array('getIndex','postSignin')));
// using this one to display user value if login and is admin
if (Auth::check() && Auth::user()->isAdmin()){
$this->user = Auth::getUser();
View::share('user', $this->user);
}
}
// main admin page
public function getIndex(){
$this->layout->content = View::make('admin.login');
}
// get the dashboard page
public function getDashboard() {
$this->layout->content = View::make('admin.dashboard');
}
// missing pages all redirect to dashboard if user is logged in.
public function missingMethod($parameters = array()){
if (Auth::check() && Auth::user()->isAdmin())
$this->getDashboard();
else
$this->getIndex();
}
Here is my filters.php file :
Route::filter('auth.admin', function()
{
if(!Auth::check() && !(Auth::user()->isAdmin())){
return Redirect::guest('admin');
}
});
in my routes.php file I am doing this:
Route::controller('admin', 'AdminController');
here is what I want if you could help me :_
1) . I want to clean up my code where there is not that much checking for if user is logged and isAdmin.
2). right now if you are logged in and you go to "admin/" , it will show you the login page ? how could I fix it in an effective way.
3). also if you are not logged in and you go to "admin/dashboard" it will show you dashboard content ? how to fix
Thank you in advance for all your help :)
You can use route groups and use a single filter to validate them
Check the docs
http://laravel.com/docs/routing#route-groups
Add this in your routes.php file:
Route::group(array('before' => 'auth.admin'), function() {
Route::controller('admin', 'AdminController');
})
Declare filter in filters.php file:
Route::filter('auth.admin', function(){
// Assumed you have a '/login' url
if (Auth::guest() || (Auth::check() && !Auth::user()->isAdmin())) {
return Redirect::guest('login');
}
});
Also make sure you have the user()->isAdmin() method in your User model that you are using and it checks whether the user is an admin or not and returns a Boolean value, TRUE if the user is an admin otherwise FALSE.
What is best way to have page access restricted to authentication role / permit? I was thinking using Auth::user()->role for detection which will be put into every route section. So, is there any better way or best practice for doing this in Laravel 4?
Thank you.
You may try something like this (use a filter for role checking)
Route::filter('role', function()
{
return Auth::user()->role;
});
Then in your routes, you can use this (role) filter like
Route::get('protectedPage1', array('before'=>'role', function($role) {
if($role != 'admin') {
return Redirect::to('home');
}
}));
Route::get('protectedPage2', array('before'=>'role', function($role) {
if($role != 'admin') {
return Redirect::to('home');
}
}));
Update:
Route::filter('role', function()
{
if(Auth::user()->role != 'admin') {
return Redirect::to('home');
}
});
Route::get('protectedPage1', array('before'=>'role', function() {
// do your job
}));