Use Multiple Middleware for Combined Routes in Laravel 8 - php

I'm going to assign all routes to Admin role, a few routes to operation role and a few routes to other roles in my App. I've tried to use group middleware in Laravel 8.
The code for Admin Role alone works fine. But, when I add middleware to other roles in the route group, it's not functioned how I expected.
My code:
Web.php:
Route::middleware(['role:Admin'])->group(function () {
Route::get('/', function () {
return redirect('/home');
});
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::get('/employee_register', [App\Http\Controllers\EmployeeRegisterController::class, 'index'])->name('employee_register');
Route::post('/employee_register', [App\Http\Controllers\EmployeeRegisterController::class, 'save'])->name('employee_save');
Route::post('/DoAsync', [App\Http\Controllers\AjaxController::class,'ajaxTask'])->middleware('only.ajax');
Route::get('/job_booking', [App\Http\Controllers\JobBookingController::class, 'index'])->name('job_booking');
Route::post('/DoAsync_jb', [App\Http\Controllers\JobBookingAjaxController::class,'ajaxTask'])->middleware('only.ajax');
Route::post('/DoAsync_ai', [App\Http\Controllers\AssignInchargeAjaxController::class,'ajaxTask'])->middleware('only.ajax');
});
Route::middleware(['role:operation'])->group(function () {
Route::get('/', function () {
return redirect('/job_booking');
});
Route::get('/home', function(){
return redirect('/job_booking');
})->name('home');
Route::get('/job_booking', [App\Http\Controllers\JobBookingController::class, 'index'])->name('job_booking');
Route::post('/DoAsync_jb', [App\Http\Controllers\JobBookingAjaxController::class,'ajaxTask'])->middleware('only.ajax');
Route::post('/DoAsync_ai', [App\Http\Controllers\AssignInchargeAjaxController::class,'ajaxTask'])->middleware('only.ajax');
});
The Middleware
(EnsureUserHasRole):
class EnsureUserHasRole
{
public function handle(Request $request, Closure $next, string $role)
{
//I received Call to a member function roles() on null error when accessing login and logout.
// So, I used this to avoid role check on login & logout routes.
if ( $request->route()->named('login') || $request->route()->named('logout') ) {
return $next($request);
}
elseif ($request->user()->roles()->where('role', '=', $role)->exists()) {
return $next($request);
}
abort(403);
}
}
Models:
User:
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
protected $fillable = [
'employee_id',
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function roles()
{
return $this->belongsToMany(Role::class, 'role_user');
}
}
Role:
class Role extends Model
{
use HasFactory;
public function users()
{
return $this->belongsToMany(User::class, 'role_user');
}
}
Without the second Middleware (middleware(['role:operation'])), all routes would be accessed. But, then adding it, the if condition in EnsureUserHasRole middleware executes the abort(403)
Should I use any if in the middleware in web.php?
Note: middleware('only.ajax') has been used to ensure the controller is accessed only on Ajax call

You are duplicating the routes. If you run php artisan route:list you will notice that half of your routes are missing.
Lets take an example route '/', what you did is similar to this:
Route::get('/', function () {
return redirect('/home');
})->middleware(['role:Admin']);
Route::get('/', function () {
return redirect('/job_booking');
})->middleware(['role:operation']);
As you can see routes duplicates.
To avoid this you need to add prefix to your routes like:
Route::get('/admin', function () {
return redirect('/home');
})->middleware(['role:Admin']);
Route::get('/operation', function () {
return redirect('/job_booking');
})->middleware(['role:operation']);
Check out Laravel Routing for more information.

Related

Laravel 6 - Auth::guard('user')->user return null

I create a multiple Authentication in Laravel. When I login with user, on debug in post login method, after Auth::guard('user')->attempLogin..... I see a user but after redirect to HomeController this return null.
How to resolve? I'm beginner in Laravel.
Thank's!!!
/routes/auth/user.php
Route::prefix('backoffice')->name('user.')->namespace('User')->middleware('user')->group(function () {
Auth::routes();
Route::get('home', 'HomeController#index')->name('home');
});
/routes/web.php
Route::group(['middleware' => 'web'], function() {
require 'auth/user.php';
Route::get('/', function () {
return view('welcome');
});
Route::get('/home', 'HomeController#index')->name('home');
Route::resource('cadastro', 'CadastroController');
});
/app/Controllers/User/Auth/LoginController - #post Login
public function login(Request $request) {
$credentials = [
'username' => $_POST['username'],
'password' => $_POST['password']
];
Auth::guard('user')->attempt($credentials, false);
//dd('auth', Auth::guard('user'));
return redirect()->intended('/backoffice/home');
}
/app/Controllers/User/HomeController
public function __construct()
{
$this->middleware('user');
dd('after middleware', Auth::guard('user'), Auth::guard('user')->user());
}
public function index()
{
return view('user.home');
}
By default, Laravel doesn't ship with auth guard user. Perhaps you meant to use web guard i.e Auth::guard('web'). Auth::guard()->user() should return the logged in user object if a user is logged in.
Also, the default middleware for checking logged in user is auth, not user. So, your route might look like this: Route::prefix('backoffice')->name('user.')->namespace('User')->middleware('auth')->group(function () {});, except you've defined a custom middleware in app/Http/Kernel.php $routeMiddleware array with alias user

Laravel redirect to specific route when user is not logged

If i go to http://www.yourdomain.com/admin/login i see my login page.
If i go to http://www.yourdomain.com/admin/example i have the redirect to http://www.yourdomain.com/login without the admin.
My web routes:
Auth::routes();
Route::prefix('admin')->group(function() {
Route::get('/login','Auth\AdminLoginController#showLoginForm')->name('admin.login');
Route::post('/login','Auth\AdminLoginController#login')->name('admin.login.submit');
Route::get('/manifiesto','AdminController#getIndex')->name('admin.dashboard');
Route::get('/logout','Auth\AdminLoginController#logout')->name('admin.logout');
Route::get('/trabajadores','AdminController#showTrabajadores')->name('admin.trabajadores');
Route::get('/clientes','AdminController#showClientes')->name('admin.clientes');
Route::get('/proyectos','AdminController#showProyectos')->name('admin.proyectos');
Route::get('/administradores','AdminController#showAdmins')->name('admin.administradores');
});
When i put some url with the /admin before and user isn't logged, i want to redirect to /admin/login.
Thanks.
More info:
App/http/Controllers/Auth/AdminLoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Auth;
class AdminLoginController extends Controller
{
protected $loginPath = 'admin/login';
public function __construct()
{
$this->middleware('guest:admin', ['except' => ['logout']]);
}
public function showLoginForm()
{
return view('backend.public.pages.login');
}
public function login(Request $request)
{
//validate the form data
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:6'
]);
//attempt to log the user in
if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->remember)){
//if successful, then redirect to their intended location
return redirect()->intended(route('admin.dashboard'));
}
return redirect()->back()->withInput($request->only('email','remember'));
}
public function logout()
{
Auth::guard('admin')->logout();
return redirect('/');
}
}
App\Http\Middleware\AdminAuthenticate.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class AdminAuthenticate
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('admin/login'); // <--- here
}
}
return $next($request);
}
}
Create an middleware
php artisan make:middleware AuthAdmin
Check for guest in the handle method of the middleware
public function handle($request, Closure $next)
{
if (Auth::guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('admin/login');
}
}
return $next($request);
}
Add a key to the middleware in app/Http/Kernel.php in $routeMiddleware array
'auth_admin' => \App\Http\Middleware\AuthAdmin::class
Attach the auth_admin middleware to the group
Route::group(['prefix' => 'admin', 'middleware' => 'auth_admin'], function() {
// Your admin routes except login
});
write bellow code in your route.php file
Route::group(array('prefix' => 'admin'), function() {
Route::controller('login', 'AdminloginController');
});
Route::group(array('before' => 'admin_ajax', 'prefix' => 'admin'), function()
{
//route for pages which are render after login
});
Route::get('/admin', function() {
return View::make('admin.loginform');
});
And Write bellow code in your filter.php file
Route::filter('admin_ajax', function() {
if (!Auth::admin()->check()) {
return Redirect::to('admin/login');
} else {
}
});
And if you are using laravel 5.4
Route::get('/manage', function () {
return redirect('manage/login');
});
Route::group(['prefix' => 'manage'], function() {
//login bypass for the below listed controllers
Route::resource('login', 'AdminLoginController#showLoginForm');
Route::post('dologin', 'AdminLoginController#login');
});
All you can do is add the auth middleware like this :
Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function() {
Route::get('/login','Auth\AdminLoginController#showLoginForm')->name('admin.login');
Route::post('/login','Auth\AdminLoginController#login')->name('admin.login.submit');
Route::get('/manifiesto','AdminController#getIndex')->name('admin.dashboard');
Route::get('/logout','Auth\AdminLoginController#logout')->name('admin.logout');
Route::get('/trabajadores','AdminController#showTrabajadores')->name('admin.trabajadores');
Route::get('/clientes','AdminController#showClientes')->name('admin.clientes');
Route::get('/proyectos','AdminController#showProyectos')->name('admin.proyectos');
Route::get('/administradores','AdminController#showAdmins')->name('admin.administradores');
});
But by default this will redirect to /login, if you want to override this you have two chocies depending on if you have other type of users that uses the /login route or not !!
If NO ONE uses /login route
1- You need to modify App\Http\Middleware\Authenticate::handle() method and change /login to admin/login.
2- Then you need to add $loginPath property to your \App\Http\Controllers\Auth\AuthController class.
Authenticate
namespace App\Http\Middleware;
class Authenticate {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('admin/login'); // <--- here
}
}
return $next($request);
}
}
AuthController
namespace App\Http\Controllers\Auth;
class AuthController extends Controller
{
protected $loginPath = 'admin/login'; // <--- here
// ... other properties, constructor, traits, etc
}
If there is someone using /login route
You must create you own middleware and do what it takes for auth checking in the handle method with redirecting to your admin/liging route :)
In this case :
Add the following line in $routeMiddleware property at app/Http/Kernel.php file
'adminAuth' => \App\Http\Middleware\YourNewMiddleware::class,
Don't forget to add your new middleware in route group as follow
Route::group(['prefix' => 'admin', 'middleware' => 'adminAuth'], function()
{
// your admin routes
});
Make an another middleware for admin. follow the step
Make a file named AdminAuthenticate in app/Http/Middleware location and copy the content of Authenticate in New file
change the Class name as AdminAuthenticate
Change the content of handle function as show below
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/admin/login');
}
}
return $next($request);
}
Add the following line in $routeMiddleware array at app/Http/Kernel.php file
'AdminAuth' => \App\Http\Middleware\AdminAuthenticate::class,
Now everything is okay. just add your new middleware in route group as follow
Route::group(['prefix' => 'admin', 'middleware' => 'AdminAuth'], function()
{
// all admin routes
});
Or you can add new middleware to constructor function of every admin controller as like below
$this->middleware('AdminAuth');

Auth::user() returns null

I use Laravel 5.2 and have a problem with middleware.
There is the code in the routes.php
use Illuminate\Contracts\Auth\Access\Gate;
Route::group(['middleware' => 'web'], function () {
Route::auth();
Route::get('/', 'HomeController#index');
});
Route::group(['prefix'=>'admin', 'middleware' => 'admin'], function(){
Route::get('/', function(){
return view('admin.index');
});
Route::get('/user', function(){
return view('admin.user');
});
});
Kernel.php:
protected $routeMiddleware = [
...
'admin' => \App\Http\Middleware\AdminPanel::class,
];
AdminPanel.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use App\Role;
class AdminPanel
{
public function handle($request, Closure $next)
{
$user = Auth::user();
dd($user);
if($user){
$role = Role::whereName('admin')->first();
if($user->hasRole($role)){
return $next($request);
}
}
return redirect('/');
}
So, $user = Auth::user() always return null.
Thanks for suggestions!
I faced a situation where Auth::user() always returns null, it was because I was trying to get the User in a controller's constructor.
I realized that you can't access the authenticated user in your controller's constructor because the middleware has not run yet.
As an alternative, you can define a Closure based middleware directly in your controller's constructor.
namespace App\Http\Controllers;
use App\User;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
class ProjectController extends Controller
{
protected $user;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->user = Auth::user();
return $next($request);
});
}
}
Any route that uses Auth() must be encapsulated in the web middleware. You're close, just move your Route::group(['prefix' => 'admin'], ...) into the group above.
Route::group(['middleware' => 'web'], function () {
Route::auth();
Route::get('/', 'HomeController#index');
// Moving here will ensure that sessions, csrf, etc. is included in all these routes
Route::group(['prefix'=>'admin', 'middleware' => 'admin'], function(){
Route::get('/', function(){
return view('admin.index');
});
Route::get('/user', function(){
return view('admin.user');
});
});
});
Define middleware in the constructer of your controller and it will do the trick here
public function __construct()
{
$this->middleware('auth:api');
}
I had the same problem because i did not set the table name.
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'users';
I found a solution in an old code
function getAuth($guard, $get)
{
return auth($guard)->user()->$get;
}
add this ^ as a helper function and use it wherever you want
ex:
getAuth('user', 'id');
just include your authentication middleware in call
$user = auth('middleware')->user()
Route::middleware('auth:api')->group(function () {
Route::get('/details', 'UserController#details');
});
My Auth::user() return null in view when
I don't have users table in database
I don't have id field as primary key of table users

Laravel 5.1 page authentication using routes

I'm working on a site that needs an admin panel. I am currently trying to set up the authentication of that panel, though I can not find a way to deny access from any guest users (non-admins). I have a login page, of course, and after login, it routes to the admin page, though you can also go to /admin when you're not logged in.
routes.php :
Route::get('home', function(){
if (Auth::guest()) {
return Redirect::to('/');
} else {
return Redirect::to('admin');
}
});
Route::get('admin', function () {
return view('pages.admin.start');
});
MainController.php :
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class MainController extends Controller {
public function getIndex() {
return view('pages.index');
}
public function getAbout() {
return view('pages.about');
}
public function getPortfolio() {
return view('pages.portfolio');
}
public function getShop() {
return view('pages.shop');
}
public function getContact() {
return view('pages.contact');
}
/*public function getAdmin() {
return view('pages.admin.start');
}*/
}
I could really use some help here, because I'm totaly stuck, and yes, I have read the documentation, though maybe I'm just missing something.
Assuming you have a line like this:
'auth' => 'App\Http\Middleware\Authenticate',
in your app/Http/Kernel.php file:
put all the routes you need "authenticated" inside the grouping, but keep the "guest" routes outside of them :
Route::get('home', function(){
if (Auth::guest()) {
return Redirect::to('/');
} else {
return Redirect::to('admin');
}
});
Route::group( ['middleware' => 'auth' ], function(){
Route::get('admin', function () {
return view('pages.admin.start');
});
Route::just-another-route()...;
Route::just-another-route()...;
});
Documentation: http://laravel.com/docs/5.1/routing#route-groups
You should use a Middleware to handle authentication of your users
1) First you have to create a middleware that will check if the user requiring the page is an admin, and if not you have to redirect; something like this:
class AdminMiddleware
{
public function handle(Request $request, Closure $next )
{
//if User is not admin
//redirect to no permess
return $next($request);
}
}
2) Then you have to bind the middleware to the routes you want to be accessible only from an admin user:
//bind the middleware to all the routes inside this group
Route::group( ['middleware' => 'adminmiddleware' ], function()
{
Route::get('admin', function () {
return view('pages.admin.start');
});
//other routes
});

Laravel 5 redirect loop error

I trying to make a login and admin script, the problem is that I have a redirect loop I dont know why.
I want the login users and can be in the / path not /home.
If change return new RedirectResponse(url('/')); to return new RedirectResponse(url('/anotherpage')); it works but I want to be /
Routes:
Route::get('/', [
'as' => 'home', 'uses' => 'HomeController#index'
]);
// Tutorials Routes
Route::get('/tutorials', 'HomeController#tutorials');
Route::get('/tutorials/{category?}', 'HomeController#tutorialsCategory');
Route::get('/tutorials/{category?}/{lesson?}', 'HomeController#tutorialsLesson');
// Courses and Series Routes
Route::get('/courses-and-series', 'HomeController#coursesandseries');
// Admin Routes
Route::group(['middleware' => 'App\Http\Middleware\AdminMiddleware'], function()
{
Route::get('/admin', function()
{
return 'Is admin';
});
});
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
Admin middleware:
public function handle($request, Closure $next)
{
if (Auth::user()->type != 'Admin')
{
return abort(404);
}
return $next($request);
}
RedirectIfAuthenticated:
public function handle($request, Closure $next)
{
if ($this->auth->check())
{
return new RedirectResponse(url('/'));
}
return $next($request);
}
Home Controller:
class HomeController extends Controller {
public function __construct()
{
$this->middleware('guest');
}
public function index()
{
return view('home');
}
public function tutorials()
{
return view('pages.tutorials');
}
public function tutorialsCategory()
{
return view('pages.tutorials');
}
public function tutorialsLesson()
{
return view('pages.single');
}
public function coursesandseries()
{
return view('pages.coursesandseries');
}
public function single()
{
return view('pages.single');
}
}
You are having these redirection loops because all the methods in HomeController are protected by Guest Middleware.
Since you wish to redirect authenticated users to HomeController#index
Remove $this->middleware('guest'); from HomeController
or
Modify the Guest Middleware to ignore index method
$this->middleware('guest', ['only' => ['tutorials','tutorialsCategory']])
List other methods you wish to protect with Guest Middleware excluding Index method

Categories