Related
Trying to play with Laravel today for the first time. I am getting the following error when I attempt to visit localhost/project/public:
InvalidArgumentException
Route [login] not defined.
app/routes.php:
<?php
Route::get('/', 'HomeController#redirect');
Route::get('login', 'LoginController#show');
Route::post('login', 'LoginController#do');
Route::get('dashboard', 'DashboardController#show');
app/controllers/HomeController.php:
<?php
class HomeController extends Controller {
public function redirect()
{
if (Auth::check())
return Redirect::route('dashboard');
return Redirect::route('login');
}
}
app/controllers/LoginContoller.php:
<?php
class LoginController extends Controller {
public function show()
{
if (Auth::check())
return Redirect::route('dashboard');
return View::make('login');
}
public function do()
{
// do login
}
}
app/controllers/DashboardController.php:
<?php
class DashboardController extends Controller {
public function show()
{
if (Auth::guest())
return Redirect::route('login');
return View::make('dashboard');
}
}
Why am I getting this error?
Try to add this at Header of your request: Accept=application/json postman or insomnia add header
You're trying to redirect to a named route whose name is login, but you have no routes with that name:
Route::post('login', [ 'as' => 'login', 'uses' => 'LoginController#do']);
The 'as' portion of the second parameter defines the name of the route. The first string parameter defines its route.
In app\Exceptions\Handler.php
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
return redirect()->guest(route('auth.login'));
}
Laravel has introduced Named Routes in Laravel 4.2.
WHAT IS NAMED ROUTES?
Named Routes allows you to give names to your router path. Hence using the name we can call the routes in required file.
HOW TO CREATE NAMED ROUTES?
Named Routes created in two different way : as and name()
METHOD 1:
Route::get('about',array('as'=>'about-as',function()
{
return view('about');
}
));
METHOD 2:
Route::get('about',function()
{
return view('about');
})->name('about-as');
How we use in views?
about-as
Hence laravel 'middleware'=>'auth' has already predefined for redirect as login page if user has not yet logged in.Hence we should use as keyword
Route::get('login',array('as'=>'login',function(){
return view('login');
}));
You need to add the following line to your web.php routes file:
Auth::routes();
In case you have custom auth routes, make sure you /login route has 'as' => 'login'
In case of API , or let say while implementing JWT . JWT middleware throws this exception when it couldn't find the token and will try to redirect to the log in route.
Since it couldn't find any log in route specified it throws this exception .
You can change the route in "app\Exceptions\Handler.php"
use Illuminate\Auth\AuthenticationException;
protected function unauthenticated($request, AuthenticationException $exception){
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest(route('ROUTENAME'));
}
Am late to the party. if your expectation is some sort of json returned other than being redirected, then edit the exception handler so do just that.
Go to go to App\Exceptions\Handler.php
Then edit this code:
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
to
public function render($request, Exception $exception)
{
return response()->json(
[
'errors' => [
'status' => 401,
'message' => 'Unauthenticated',
]
], 401
);
}
Try this method:
look for this file
"RedirectifAuthenticated.php"
update the following as you would prefer
if (Auth::guard($guard)->check()) {
return redirect('/');
}
$guard as an arg will take in the name of the custom guard you have set eg. "admin" then it should be like this.
if (Auth::guard('admin')->check()) {
return redirect('/admin/dashboard');
}else{
return redirect('/admin/login');
}
I ran into this error recently after using Laravel's built-in authentication routing using php artisan make:auth. When you run that command, these new routes are added to your web.php file:
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
I must have accidentally deleted these routes. Running php artisan make:auth again restored the routes and solved the problem. I'm running Laravel 5.5.28.
Route::get('/login', function () {
return view('login');})->name('login');
Name your login route if using your own custom auth system.
Route::post('login', 'LoginController#login')->name('login')
works very well and it is clean and self-explanatory
Laravel ^5.7
The Authenticate Middleware
Laravel ^5.7 includes new middleware to handle and redirect unauthenticated users.
It works well with "web" guard... of course the "login" route (or whatever you name your login route) should be defined in web.php.
the problem is when your are using custom guard. Different guard would redirect unauthenticated users to different route.
here's a quick workaround based on John's response (it works for me).
app/Http/Middleware/Authenticate.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* #var array
*/
protected $guards = [];
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string[] ...$guards
* #return mixed
*
* #throws \Illuminate\Auth\AuthenticationException
*/
public function handle($request, Closure $next, ...$guards)
{
$this->guards = $guards;
return parent::handle($request, $next, ...$guards);
}
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* #param \Illuminate\Http\Request $request
* #return string
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
if (in_array('admin', $this->guards)) {
return route('admin.login');
}
return route('login');
}
}
}
Source : Issue #26292
Replace in your views (blade files) all
{{route('/')}} ----- by ----> {{url('/')}}
If someone getting this from a rest client (ex. Postman) - You need to set the Header to Accept application/json.
To do this on postman, click on the Headers tab, and add a new key 'Accept' and type the value 'application/json'.
**Adding this for the future me.**
I encountered this because I was reusing Laravel's "HomeController", and adding my custom functions to it. Note that this controller calls the auth middleware in its __construct() method as shown below, which means that all functions must be authenticated. No wonder it tries to take you to login page first. So, if you are not using Laravel's authentication scafffolding, you will be in a mess. Disable the constructor, or do as you seem fit, now that you know what is happening.
public function __construct()
{
$this->middleware('auth');
}
//In Laravel 8
Route::post('login', [LoginController::class, 'do'])->name('login');
If using passport as api do:
routes/web.php:
Route::get('login', function() {
return response()->json(['message' => 'Unauthorized.'], 401);
});
Route::post('login', [ 'as' => 'login']);
For Laravel 8 I face the problem while access home url after creating login register system
First there is no route exists with the name login
Just add a route name like this
for single method like
Route::post('put url here',[Your Controller::class,'method name'])->name('login');
for multiple method like
Route::match(['get','post'],'put url here',[Your Controller::class,'method name'])->name('login');
Route must be valid, should give route name.
Route::group([
'prefix' => 'v1'
], function () {
Route::post('/login', [userController::class, 'loginAction'])->name('login');
});
I'm experimenting with Middleware in my Laravel application. I currently have it set up to run on every route for an authenticated user, however, I want it to ignore any requests that begin with the setup URI.
Here is what my CheckOnboarding middleware method looks like:
public function handle($request, Closure $next)
{
/**
* Check to see if the user has completed the onboarding, if not redirect.
* Also checks that the requested URI isn't the setup route to ensure there isn't a redirect loop.
*/
if ($request->user()->onboarding_complete == false && $request->path() != 'setup') {
return redirect('setup');
} else {
return $next($request);
}
}
This is being used in my routes like this:
Route::group(['middleware' => ['auth','checkOnboarding']], function () {
Route::get('/home', 'HomeController#index');
Route::get('/account', 'AccountController#index');
Route::group(['prefix' => 'setup'], function () {
Route::get('/', 'OnboardingController#index')->name('setup');
Route::post('/settings', 'SettingsController#store');
});
});
Now, if I go to /home or /account I get redirected to /setup as you would expect. This originally caused a redirect loop error hence why & $request->path() != 'setup' is in the Middleware.
I feel like this is a really clunky way of doing it, and obviously doesn't match anything after setup like the setup/settings route I have created.
Is there a better way to have this Middleware run on all routes for a user, but also set certain routes that should be exempt from this check?
There's nothing wrong with what you're doing, however, I would suggest splitting your route groups up instead i.e.:
Route::group(['middleware' => ['auth', 'checkOnboarding']], function () {
Route::get('/home', 'HomeController#index');
Route::get('/account', 'AccountController#index');
});
Route::group(['prefix' => 'setup', 'middleware' => 'auth'], function () {
Route::get('/', 'OnboardingController#index')->name('setup');
Route::post('/settings', 'SettingsController#store');
});
Alternatively, have a parent group for your auth:
Route::group(['middleware' => 'auth'], function () {
Route::group(['middleware' => 'checkOnboarding'], function () {
Route::get('/home', 'HomeController#index');
Route::get('/account', 'AccountController#index');
});
Route::group(['prefix' => 'setup'], function () {
Route::get('/', 'OnboardingController#index')->name('setup');
Route::post('/settings', 'SettingsController#store');
});
});
This will also mean you can remove the extra condition in your middleware:
/**
* Check to see if the user has completed the onboarding, if not redirect.
* Also checks that the requested URI isn't the setup route to ensure there isn't a redirect loop.
*/
return $request->user()->onboarding_complete ? $next($request) : redirect('setup');
Hope this helps!
You can utilize the Controller class for this with pretty spectacular results.
If you create a __construct function inside of HTTP/Controllers/Controller.php then you can declare middleware to run on every controller action and even declare exceptions as needed.
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct(){
$this->middleware('auth',['except' => ['login','setup','setupSomethingElse']]);
}
}
Be careful not to put any of the standard index, store, update, destroy functions in the exception or you'll open up potential security issues.
Since Laravel 7.7 you can use excluded_middleware like this:
Route::group(['middleware' => ['auth','checkOnboarding']], function () {
Route::get('/home', 'HomeController#index');
Route::get('/account', 'AccountController#index');
Route::group([
'prefix' => 'setup',
'excluded_middleware' => ['checkOnboarding'],
], function () {
Route::get('/', 'OnboardingController#index')->name('setup');
Route::post('/settings', 'SettingsController#store');
});
});
In Laravel 8.x you can also use the withoutMiddleware() method to exclude one or many route to a group middleware
Route::middleware('auth')->group(function () {
Route::get('/edit/{id}',[ProgramController::class, 'edit'])->name('edit');
Route::get('/public', [ProgramController::class, 'public'])
->name('public')->withoutMiddleware(['auth']);
});
Check also the official doc: Here
There are 2 ways to go over this problem
Try screening your routes in routes file web.php or api.php
skip routes in middleware
In case of global middleware (middleware that you want to run before all routes), you should go with skipping routes in middleware.
For example:
//add an array of routes to skip santize check
protected $openRoutes = [
'setup/*',
];
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(!in_array($request->path(), $this->openRoutes)){
//middleware code or call of function
}
return $next($request);
}
For other middleware, you can easily skip in routes file and group routes based on your middleware.
For example:
Route::group(['middleware' => 'checkOnboarding'], function () {
Route::get('/home', 'HomeController#index');
Route::get('/account', 'AccountController#index');
});
Route::group(['prefix' => 'setup'], function () {
Route::get('/', 'OnboardingController#index')->name('setup');
Route::post('/settings', 'SettingsController#store');
});
Routes on which you dont want the middleware to run , simply put them outside of the function:
//here register routes on which you dont want the middleware: checkOnboarding
Route::group(['middleware' => ['auth','checkOnboarding']], function () {
//routes on which you want the middleware
});
I have a Route group in laravel which has middleware of auth
Route::group(['middleware'=>'auth', function()
{
//Routes
});
Now these routes are only available to logged in users. I have a situation that logged in users have privileges. I have some routes that are only to be visited by logged in users AND if they have privilege of OWNER
In function I have started a session and stored privilege value.
I did something like this
Route::group(['middleware'=>'auth', function()
{
//Routes
if(session::get('privilege')
{
//Routes
}
});
This isn't working neither it's appropriate method. Can anyone tell me how add middleware inside a middleware?
There should be no logic inside your routes file(s) - these should simply define routes and nothing else. What you should do is define middleware which verifies privileges/roles your user has, you can specify parameters which are passed to the middleware like this:
Route::group(['middleware' => 'auth', function() {
Route::get('/my-route', 'Controller#method')->middleware('role:some_role');
Route::get('/my-other-route', 'Controller#otherMethod')->middleware('role:some_other_role');
});
Then in your middleware, you can access that parameter via a third argument in the handle method. With that value, you could verify the privileged/role the user has and then decide if the user should access that route:
public function handle($request, Closure $next, $role)
{
// Do something with $role
return $next($request);
}
If you're unsure about defining your own custom middleware, check out the docs here: https://laravel.com/docs/middleware
You will need to create a custom middleware called OWNER
php artisan make:middleware Owner
Will create a middleware file for you.
Then in the public function called handle u can do something like
if (Auth::user()->privilege == "OWNER") {
return $next($request);
}
return redirect('home');
So at the end your custom middleware will look something like this:
<?php
namespace App\Http\Middleware;
use Closure;
class Owner
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->privilege == "OWNER") {
return $next($request);
}
return redirect('home');
}
}
More about Laravel Middelware here
Hello in my project I am using the auto generated password from the admin side.And when the user try to login I am checking that user changed the password or not if password is not changes I want to redirect the user at the changepassword screen. I set changepasword middleware for it but middleware do not call the changepassword redirection Link.
changepasword middleware
use Closure;
use Auth;
class ChangePassword
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ( Auth::check() && Auth::user()->isAutoPasswordChanged() )
{
return redirect('/change_password');
}
else
{
return redirect('/tests');
}
}
}
web.php
Route::group(['middleware' => 'auth', 'changepassword'], function () {
Route::resource('/tests', 'TestController');
Route::resource('/clients', 'ClientController');
});
Go to app\Http\Kernel.php
and add this to $routeMiddleware
'change_password' => \App\Http\Middleware\ChangePassword::class,
Then in your routes, replace the middle ware line with
Route::group(['middleware' => ['auth', 'changepassword']], function () {
And I also believe the logic written in ChangePassword is wrong...
It should be
if (!auth()->user()->isAutoPasswordChanged()) {
return redirect(route('auth.change.password.get'));
}
return $next($request);
First, please use the route() function instead of simple string... You will not have to change the url here, if you ever change the route from your web.php
Since you are already using the auth middleware, there is no need for you to do auth()->check().
Secondly, there should be a NOT in the condition. Because if the AutoPassword is NOT changed, only then redirect to the route, otherwise the use should be returned the next request and NOT redirected to /tests
Check registration of middleware app/Http/Kernel.php Doc
If you have a route middleware, compare the name provided in app/Http/Kernel.php
but my guess is:
'middleware' => 'auth', 'changepassword' should maybe changed in 'middleware' => ['auth', 'changepassword']
Debug if middleware itself is called
I want to create my app ( I dont want to use laravel default login system)
I want to use a middleware to be run during every HTTP request in my application except one
in laravel 5.1 documention syas I can use Global Middleware but I want to not use middleware for just login page.
what should I do ?
this is my middleware :
<?php
namespace App\Http\Middleware;
use Closure;
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if( ! session()->has('Login' ) )
{
return redirect('login');
}
return $next($request);
}
}
You can use routes group and assign your middleware to it:
Route::group(['middleware' => 'Admin'], function () {
// All of your routes goes here
});
// Special routes which you dont want going thorugh the this middleware goes here
Don't do anything to your middleware. you have the free to take that route outside the route group. so it becomes a standalone route. Or you can create a new route group and put only that one route in without that middleware. eg.
Route::group(['prefix' => 'v1'], function () {
Route::post('login','AuthenticationController');
});
Route::group(['prefix' => 'v1', 'middleware' => 'web'], function () {
Route::resource('deparments','AuthenticationController');
Route::resource("permission_roles","PermissionRolesController");
});
with this the middleware affect only the second route group
There are a couple of ways to tackle this, one is to address this in your middleware and exclude the route there, and two is to group all the routes you want to have covered by the middleware in your routes.php and then have the ones you want excluded outside of the grouping.
Tackling this in middleware
Just amend the handle function to include an if statement checking the URI requested
public function handle($request, Closure $next)
{
if ($request->is("route/you/want/to/exclude"))
{
return $next($request);
}
if( ! session()->has('Login' ) )
{
return redirect('login');
}
else
{
return redirect('login');
}
}
This method allows you to set the middleware up as global middleware and you can make multiple exclusions by extending the if statement with or $request->is().
Tackling this in routes
//Place all the routes you don't want protected here
Route::group(['middleware' => 'admin'], function () {
//Place all the routes you want protected in here
});