L5.7 includes new middleware to handle and redirect unauthenticated users.
It works well with "web" guard. But using custom guards there is no way (at least I couldn't find it) to get current guard.
Different guard would redirect authenticated users to different route, but guard is always set to "web" instead of current guard.
in auth.php - new guard is added: admin
Routes:
Route::group(['middleware' => ['auth:admin']], function () {
// routes...
});
$this->auth
returns AuthManager with protected property $guards: [admin];
but $this->auth->guard()
returns "web".
Shouldn't $this->auth->guard()
return "admin", instead of "web" SessionGuard, since this route is under middleware auth:admin?
I have same issue, right now i am handling multiple guards like this
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Support\Facades\Route;
class Authenticate extends Middleware
{
/**
* 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 (Route::is('admin.*')) {
return route('admin.login');
}
return route('login');
}
}
}
There should be a way to receive the guard name in redirectTo
method.
I was able to solve this, see how
<?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 (array_first($this->guards) === 'admin') {
return route('admin.login');
}
return route('login');
}
}
}
I did override on unauthenticated method, inside app/Exceptions/Handler.php:
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['message' => $exception->getMessage()], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'admin':
$route = 'admin.login';
break;
default:
$route = 'login';
}
return redirect()->guest(route($route));
}
In the class "Authenticate" I just override function "authenticate" and changed function "redirectTo" like this(my custom guard is "admin"):
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
protected function authenticate($request, array $guards)
{
if (empty($guards)) {
$guards = [null];
}
foreach ($guards as $guard) {
if ($this->auth->guard($guard)->check()) {
return $this->auth->shouldUse($guard);
}
}
$guard = $guards[0];
if ($guard == 'admin'){
$request->path = 'admin.';
}else{
$request->path = '';
}
throw new AuthenticationException(
'Unauthenticated.', $guards, $this->redirectTo($request)
);
}
protected function redirectTo($request)
{
return route($request->path . 'login');
}
}
Think we can add this. Just pass along the guards argument to the redirectTo
method. Feel free to send in a PR to master.
As said in the linked PRs you could easily solve this by adding a property to your middleware. So gonna close this.
thank you
In the class "Authenticate" I just override function "authenticate" and changed function "redirectTo" like this(my custom guard is "admin"):
<?php namespace App\Http\Middleware; use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\Middleware\Authenticate as Middleware; class Authenticate extends Middleware { protected function authenticate($request, array $guards) { if (empty($guards)) { $guards = [null]; } foreach ($guards as $guard) { if ($this->auth->guard($guard)->check()) { return $this->auth->shouldUse($guard); } } $guard = $guards[0]; if ($guard == 'admin'){ $request->path = 'admin.'; }else{ $request->path = ''; } throw new AuthenticationException( 'Unauthenticated.', $guards, $this->redirectTo($request) ); } protected function redirectTo($request) { return route($request->path . 'login'); } }
this code still gives this error
Symfony Component Debug Exception FatalThrowableError (E_ERROR)
Call to undefined method IlluminateAuthTokenGuard::attempt()
handler
just edit
$guard = $exception->guards()[0];
How can we fix this problem in Laravel 7
I have same issue, right now i am handling multiple guards like this
<?php namespace App\Http\Middleware; use Illuminate\Auth\Middleware\Authenticate as Middleware; use Illuminate\Support\Facades\Route; class Authenticate extends Middleware { /** * 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 (Route::is('admin.*')) { return route('admin.login'); } return route('login'); } } }
There should be a way to receive the guard name in
redirectTo
method.PS
I was able to solve this, see how
<?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 (array_first($this->guards) === 'admin') { return route('admin.login'); } return route('login'); } } }
Thanks. It works. But In laravel ^7.0, array_first()
does not work. It is now Arr::first().
I have same issue, right now i am handling multiple guards like this
<?php namespace App\Http\Middleware; use Illuminate\Auth\Middleware\Authenticate as Middleware; use Illuminate\Support\Facades\Route; class Authenticate extends Middleware { /** * 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 (Route::is('admin.*')) { return route('admin.login'); } return route('login'); } } }
There should be a way to receive the guard name in
redirectTo
method.PS
I was able to solve this, see how
<?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 (array_first($this->guards) === 'admin') { return route('admin.login'); } return route('login'); } } }
Thanks. It works. But In laravel ^7.0,
array_first()
does not work. It is nowArr:first().
It should be Arr::first() not Arr:first().
Just tried Arr:first() and came up with issues.
Also do not forget to add
use IlluminateSupportArr; at the beginning of the file
It worked for me this way.
I have same issue, right now i am handling multiple guards like this
<?php namespace App\Http\Middleware; use Illuminate\Auth\Middleware\Authenticate as Middleware; use Illuminate\Support\Facades\Route; class Authenticate extends Middleware { /** * 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 (Route::is('admin.*')) { return route('admin.login'); } return route('login'); } } }
There should be a way to receive the guard name in
redirectTo
method.PS
I was able to solve this, see how
<?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 (array_first($this->guards) === 'admin') { return route('admin.login'); } return route('login'); } } }
Thanks. It works. But In laravel ^7.0,
array_first()
does not work. It is nowArr:first().
It should be Arr::first() not Arr:first().
Just tried Arr:first() and came up with issues.Also do not forget to add
use IlluminateSupportArr; at the beginning of the fileIt worked for me this way.
This worked fine in Laravel 8 :)
$guard = Arr::first( $this->guards );
switch ( $guard ) {
case 'supplier':
return route( 'supplier.login.supplier' );
break;
}
Most helpful comment
I have same issue, right now i am handling multiple guards like this
There should be a way to receive the guard name in
redirectTo
method.PS
I was able to solve this, see how