I have a small dilema, i'm trying to make a login system that differentiates normal users from admin users using the laravel auth scaffolding.
The problem is it goes in a infinite redirect loop in the middleware.
After I press the login button it constantly redirects to a route and the question is, how can I solve this issue the "laravel way" or any other way for that matter.
Here are my controllers:
1. The basic home controller:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('home');
}
}
The main admin controller - entry controller:
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class Start extends Controller
{
public function index(){
return view('admin/index');
}
}
Login Controller(the default one from the auth scaffolding- modified by me, I removed the constructor):
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/home';
}
The Middleware(redirect if RedirectIfAuthenticated):
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
if(Auth::user()->type == 2){//if user type is 1 then it's an admin.
return redirect()->route('web-admin');
}else{
return redirect()->route('home');
}
}
return $next($request);
}
}
The route file(web routes)
Route::get('/', function () {
return view('index');
});
Auth::routes();
Route::middleware(['auth','guest'])->group(function() {
Route::get('home',['as'=>'home', 'uses'=>'HomeController#index']);
Route::get('web-admin',['as'=>'web-admin', 'uses'=>'Admin\Start#index']);
});
The guest/RedirectIfAuthenticated redirects any request to corresponding home route for authenticated users. The problem is that admin home route is behind this middleware as well, that's why it keeps redirecting to the same page.
You need to remove the guest middleware from the route group - it should only be applied to routes that should be available to unauthenticated users only.
For sure this is an infinite loop because you applied both guest and auth middle ware to your routes, so also authenticated users will be redirected and this is an infinite loop.
Keep the RedirectIfAuthenticated.php as its original code and redirect authenticated users inside your main controller based on their type:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
// if type 1 is admin, why did you redirect type 2 to web-admin?!
if($request->user()->type == 2) { //if user type is 1 then it's an admin.
return redirect()->route('web-admin');
}
return view('home');
}
}
You may do same redirection in your admin controller for normal users to redirect them back in case they try to access admin page.
Additionally modify web.php routes as following:
Route::get('/', function () {
if(auth()->user()->type == 2) { //if user type is 1 then it's an admin.
return redirect()->route('web-admin');
} else {
return redirect()->route('home');
}
})->middleware('auth');
Auth::routes();
Route::middleware('auth')->group(function() {
Route::get('home',['as'=>'home', 'uses'=>'HomeController#index']);
Route::get('web-admin',['as'=>'web-admin', 'uses'=>'Admin\Start#index']);
});
Related
I have a column in my User table named role with 2 possible values--"Admin" and
"Driver".
All my crud routes are protected with Auth middleware, but I'd like to further secure a few of those routes.
For example I'd like to have the "Create" routes only accessible by Users with the role column equalling "Admin". I wasn't sure how to go about this, so I can't provide examples of what I've tried.
web.php
...
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/users', App\Http\Livewire\User\Index::class)->name('users.index');
Route::get('/user/{user}/edit', App\Http\Livewire\User\Edit::class)->name('user.edit');
/* This is the route I want to protect to just "Admin" role */
Route::get('/user/create', App\Http\Livewire\User\Create::class)->name('user.create');
...
You can create a middleware with the artisan command
php artisan make:middleware IsAdminMiddleware
Then add something like this in the handle function of your middleware.
public function handle(Request $request, Closure $next)
{
// This validation assumes you can access role from User Model
if ($request->user()->role != "Admin") {
return response()->json(['error' => 'you are not an admin!'], 403);
}
return $next($request);
}
Finally add the middleware on your Routes
Route::get('/user/create', App\Http\Livewire\User\Create::class)
->middleware(IsAdminMiddleware::class) // <<----
->name('user.create');
For more info refer to middleware the docs at laravel.
You can use authorization in laravel for your case
in laravel you can use gate or policy for further feature
https://laravel.com/docs/9.x/authorization
Gate
define gate in App\Providers\AuthServiceProvider on method boot
use Illuminate\Support\Facades\Gate;
use Illuminate\Auth\Access\Response;
use App\Models\User;
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('create', function (User $user) {
return ($user->role == 'Admin')
? Response::allow()
: Response::deny('You must be an administrator.');
});
}
On your controller
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class CreateController extends Controller
{
public function create(Request $request)
{
$user = Auth::user();
if (Gate::allows('create', $user)) {
//create
}
}
}
I have a middleware that redirects to the Login page and everything works fine:
*If I try to enter a page restricted by this middleware I am sent to login page and then I'm sent to that page.
*If I type /login directly, I will be redirected to /about.
I'm using a custom guard called "client".
Here is my code:
<?php
namespace App\Http\Middleware;
use Illuminate\Support\Facades\Auth;
use Closure;
class ClientLoggedIn
{
public function handle($request, Closure $next)
{
if (!Auth::guard('client')->check()) {
session(['url.intended' => url()->full()]);
return redirect()->route('login');
}
return $next($request);
}
}
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected function redirectTo()
{
$intendedURL = request()->session()->get('url.intended');
if (isset($intendedURL)) {
return $intendedURL;
}
return '/about';
}
public function __construct()
{
$this->middleware('guest:client')->except('logout');
}
protected function guard()
{
return Auth::guard('client');
}
public function showLoginForm()
{
return view('auth.login');
}
}
Whenever I click the back button after the authentication, however, a redirect to the site home (localhost:8000/) occurs (the back button refers to /login)
My question is: is there some configuration or callback that sets it to the home? I thought it would be the redirectTo, but it doesn't seem to be it since it is already set to /about. For what I know, when I click back doesn't occur a request to the server, so, how it works and how to change it?
Thanks in advance.
I'm making an application which requires a user and password for access. Every user should face the login view. Currently, writing the URL manually, I can access all the routes without login. What I want is to redirect every unauthenticated user to the login view, so that they can't see anything else until they log in.
LoginController
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
public function redirectTo() {
$isAuth = Auth::check();
if ($isAuth) {
return redirect('dashboard');
} else {
return redirect('login');
}
}
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function logout(Request $request)
{
Auth::logout();
return redirect('/login');
}
}
Routes
<?php
Route::get('/', function () {
return view('home');
});
Route::resource('project','ProjectController');
Route::resource('client','ClientController');
Route::resource('task','TaskController');
Route::resource('people','PeopleController');
Route::get('/login', function () {
return view('login');
});
Route::get('logout', '\App\Http\Controllers\Auth\LoginController#logout');
Auth::routes();
Route::get('/dashboard', 'DashboardController#index');
You should use a middleware for that. To get info on what a middleware is check here laravel.com/docs/master/middleware
Let's see how you can use the default Laravel's auth middleware for this purpose:
First of all get rid of your AdminBaseController and use only AdminController
Then you have to check that the auth middleware is enabled in the file app\Http\Kernel.php
You should have the line:
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
This means that the middleware is active and usable for your routes.
Now let's go inside the middleware class in app\Http\Middleware\Authenticate.php to specify the middleware's behaviour :
this method will be triggered before your controller constructor
public function handle($request, Closure $next)
{
//check here if the user is authenticated
if ( ! $this->auth->user() )
{
// here you should redirect to login
}
return $next($request);
}
Now the only thing left to do is to decide for what routes you should apply the middleware. Let's suppose you have two routes that you want to be only accessible from authenticated users, you should specify to use the middleware for these two routes in this way:
Route::group( ['middleware' => 'auth' ], function()
{
Route::get('admin/home', 'AdminController#index');
});
You should move your Auth::routes() before your first route
<?php
Auth::routes()
Route::get('/', function () {
return view('home');
});
And use auth middleware in your controllers where you want only authenticated user.
public function __construct()
{
$this->middleware('auth');
}
Move your Auth:Routes(); right after
Route::get('/', function () {
return view('home');
});
Then all your routes will be auth protected.
After I logout of my laravel application, in the browser I press the button to backward (go back) and then I see the dashboard.
I want to eliminate this "session" that laravel mantein if I go back.
can anyone help me?
EDIT: I have two login files, one is inside the Controllers/Auth and another is inside the Controller/. I'm sure this is not a good practice, but it's keeping my system up and running. how to solve this?
Controllers/Auth/LoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Session;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/';
/**
* Create a new controller instance.
*
* #return void
*/
private $user;
}
my Login Controllers/LoginController.php ->
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Session;
class LoginController extends Controller
{
private $user;
public function logout(){
Auth::logout();
\Session::flash('success',"logout");
return redirect()->route('login');
}
}
my DashboardController ->
use App\Authorization;
use App\BackLog;
use App\Key;
use App\isKeyInUse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
class DashboardController extends Controller
{
public function index() {
return view('dashboard');
}
}
my web.php ->
<?php
Route::get('/', 'LoginController#login')->name('login');
Route::get('auth/logout', 'Auth\LoginController#logout')->name('logout');
Route::get('/dashboard', 'DashboardController#index')->name('dashboard')->middleware('auth');
Route::post('/dashboard/getKey', 'DashboardController#getKey')->name('dashboard.key')->middleware('auth');
This is happening because caching. to prevent that we can create a middleware that intercepts every request and set the cache to expire in0 time and thus it will force the page to reload when the user press the back button here's the steps to create the middleware :
first
create a middleware i will call it MyAuth:
php artisan make:middleware MyAuth
second
register the middleware in app/Http/kernel.php
protected $routeMiddleware = [
...,
'my_auth' => \App\Http\Middleware\MyAuth::class,
];
third
in the newly created middleware app/Http/Middleware/MyAuth.php
public function handle($request, Closure $next, $guard = null)
{
$response = $next($request);
return $response
->withHeaders([
'Cache-Control' => 'no-store, no-cache, must-revalidate',
'Pragma'=> 'no-cache',
'Expires' => '0'
]);
}
}
Then
you can add your middleware like so:
Route::group(['middleware' => 'my_auth'], function() {
// All your routes you want to be secure
});
This code has been derived from this video
You are missing Request in logout function
public function logout(Request $request){
Auth::logout();
\Session::flash('success',"logout");
return redirect()->route('login');
}
And write in your dashboard controller
public function __construct()
{
$this->middleware('auth');
}
Insert these lines to your Dashboard controller and then check:
public function __contruct()
{
$this->middleware('auth');
}
This will check user is logged in or not? If user is loggedout, then it send to specific login page as you defined in auth middleware.
Pressing the Back button of your browser will load the previously loaded document. It is just visible but will not work for sure. For this you just have to override back press event from javascript.
See link How to Detect Browser Back Button event - Cross Browser
In Laravel 7.x, you can logout from the controller by using the following command:
Auth::logout()
I want to create a custom middleware that only if the user is authenticated and the email is a certain email to access the /admin page.
Although, when I specify my custom route and then a redirect it always says too many redirects..
Short Explanation.
User Logs in -> redirected to /home. (Works)
If user tries to access /admin and their email isn't like the one specified in the middleware, redirect to /home.
If its true, let them in /admin
My middleware is called 'admin.verify'
Routes File:
Route::get('/admin', 'AdminController#index')->name('admin.index');
AdminController:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AdminController extends Controller
{
public function __construct(){
$this->middleware(['auth', 'admin.verify']);
}
public function index(){
return view('admin.test');
}
}
Middleware:
public function handle($request, Closure $next)
{
if (Auth::check() && Auth::User()->email == 'Tester#gmail.com') {
return $next($request);
} else {
return redirect()->route('home');
}
My Home Route:
GET|HEAD | home | home| App\Http\Controllers\HomeController#index | web,auth
Home Controller:
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('home');
}
}
Use $this->middleware ('admin.verify') instead of $this->middleware(['auth, admin.verify]');. You are getting too many redirects error because both the admin middleware and the constructor are checking if the user is authenticated.
The problem is that when you access home route auth.verify method is called and when it fails it is redirected to home itself creating a loop hence too many redirects error.
Change else condition in auth.verify middleware to redirect to another page like /login