Laravel - 多重身份验证的未经身份验证的重定向问题
Laravel - Unauthenticated redirect issue with multiple authentication
我在 Laravel 5.7
中设置了多重身份验证系统
网站有一个 'admin' 部分和一个 'learner' 部分。
当您尝试访问任一站点的一部分时,如果您尚未登录,它会将您重定向到正确的登录页面。
但是,如果按照这些步骤操作,我会遇到重定向问题:
- 我尝试访问 'admin' 站点的一部分(不是登录名),这会将我重定向到管理员登录名。
- 然后如果我 link 直接进入 'learner' 页面的登录部分
并登录,而不是去主页它会重定向我
返回管理员登录。
它正确地让我登录,但不正确地重定向到另一个登录页面。
反之亦然,如果我自动重定向到 'learner' 然后 link 直接到管理员登录页面并登录。
我相信我已经将问题缩小到我放置在 Exception/Handler.php 文件中的未经验证的函数,但我不知道从那里去哪里。
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
return redirect()->guest(route($login));
}
使用每个单独的登录页面都可以正常工作。只是当您按照上述过程进行操作时,我才看到问题。
我在每个控制器中使用单独的中间件,如下所示:
管理员家庭控制器
public function __construct()
{
$this->middleware('auth');
}
管理员登录控制器:
public function __construct()
{
$this->middleware('guest')->except('logout');
}
学习者家庭控制器
public function __construct()
{
$this->middleware('auth:learner');
}
学习者登录控制器:
public function __construct()
{
$this->middleware('guest:learner')->except('logout');
}
解决方案:用 Session:forget('url.intended');
清除预期的 url
protected function unauthenticated($request, AuthenticationException $exception)
{
// dd($exception);
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
Session::forget('url.intented');
return redirect()->route($login);
}
这是我在生产环境中使用的一个示例,该应用程序有两个用户 class,这两个用户都必须登录才能访问各自的资源。用户 class 使用默认的 Laravel 身份验证,没有任何更改,但是,我的管理员 class 用户使用此自定义中间件:
<?php
namespace App\Http\Middleware;
use App\Admin;
use Closure;
use Illuminate\Support\Facades\Auth;
class AdminMiddleware
{
public function handle($request, Closure $next)
{
if (Auth::guest()) {
return redirect(route('admin.login'));
}
if (!$request->user() instanceof Admin) {
return redirect(route('restricted'));
}
return $next($request);
}
}
我在 app/Http/Kernel.php
中注册了 AdminMiddleware,如下所示:
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\AdminMiddleware::class,
/*** OTHER MIDDLEWARES ARE HERE ***/
];
在 routes/web.php
文件中,我将路由包装成这样:
Route::group(['prefix' => 'admin', 'as' => 'admin.', 'middleware' => 'auth:admin'], function () {
/**** ADMIN ROUTES ARE HERE ****/
});
Route::group(['middleware' => 'auth'], function () {
/**** CLIENT ROUTES ARE HERE ****/
});
我有一个自定义的 AdminLoginController,它覆盖了 $redirect
路径变量以及 guard()
、showLoginForm()
和 redirectTo()
函数,如下所示:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
class AdminLoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/admin/home';
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function guard()
{
return Auth::guard('admin');
}
public function showLoginForm()
{
return view('auth.admin.login');
}
public function redirectTo()
{
return route('admin.home');
}
}
最后,在 config/auth.php
中,我有以下对守卫、提供者和密码的引用:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
'passwords' => [
'admin' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
],
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
当然,这意味着我的管理员和用户存储在数据库中的不同表中,但它工作得非常好,没有任何问题,所以我完全同意。
解决方案:用 Session:forget('url.intended');
清除预期的 url
protected function unauthenticated($request, AuthenticationException $exception)
{
// dd($exception);
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
Session::forget('url.intented');
return redirect()->route($login);
}
我在 Laravel 5.7
中设置了多重身份验证系统网站有一个 'admin' 部分和一个 'learner' 部分。 当您尝试访问任一站点的一部分时,如果您尚未登录,它会将您重定向到正确的登录页面。
但是,如果按照这些步骤操作,我会遇到重定向问题:
- 我尝试访问 'admin' 站点的一部分(不是登录名),这会将我重定向到管理员登录名。
- 然后如果我 link 直接进入 'learner' 页面的登录部分 并登录,而不是去主页它会重定向我 返回管理员登录。
它正确地让我登录,但不正确地重定向到另一个登录页面。 反之亦然,如果我自动重定向到 'learner' 然后 link 直接到管理员登录页面并登录。
我相信我已经将问题缩小到我放置在 Exception/Handler.php 文件中的未经验证的函数,但我不知道从那里去哪里。
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
return redirect()->guest(route($login));
}
使用每个单独的登录页面都可以正常工作。只是当您按照上述过程进行操作时,我才看到问题。
我在每个控制器中使用单独的中间件,如下所示:
管理员家庭控制器
public function __construct()
{
$this->middleware('auth');
}
管理员登录控制器:
public function __construct()
{
$this->middleware('guest')->except('logout');
}
学习者家庭控制器
public function __construct()
{
$this->middleware('auth:learner');
}
学习者登录控制器:
public function __construct()
{
$this->middleware('guest:learner')->except('logout');
}
解决方案:用 Session:forget('url.intended');
清除预期的 urlprotected function unauthenticated($request, AuthenticationException $exception)
{
// dd($exception);
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
Session::forget('url.intented');
return redirect()->route($login);
}
这是我在生产环境中使用的一个示例,该应用程序有两个用户 class,这两个用户都必须登录才能访问各自的资源。用户 class 使用默认的 Laravel 身份验证,没有任何更改,但是,我的管理员 class 用户使用此自定义中间件:
<?php
namespace App\Http\Middleware;
use App\Admin;
use Closure;
use Illuminate\Support\Facades\Auth;
class AdminMiddleware
{
public function handle($request, Closure $next)
{
if (Auth::guest()) {
return redirect(route('admin.login'));
}
if (!$request->user() instanceof Admin) {
return redirect(route('restricted'));
}
return $next($request);
}
}
我在 app/Http/Kernel.php
中注册了 AdminMiddleware,如下所示:
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\AdminMiddleware::class,
/*** OTHER MIDDLEWARES ARE HERE ***/
];
在 routes/web.php
文件中,我将路由包装成这样:
Route::group(['prefix' => 'admin', 'as' => 'admin.', 'middleware' => 'auth:admin'], function () {
/**** ADMIN ROUTES ARE HERE ****/
});
Route::group(['middleware' => 'auth'], function () {
/**** CLIENT ROUTES ARE HERE ****/
});
我有一个自定义的 AdminLoginController,它覆盖了 $redirect
路径变量以及 guard()
、showLoginForm()
和 redirectTo()
函数,如下所示:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
class AdminLoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/admin/home';
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function guard()
{
return Auth::guard('admin');
}
public function showLoginForm()
{
return view('auth.admin.login');
}
public function redirectTo()
{
return route('admin.home');
}
}
最后,在 config/auth.php
中,我有以下对守卫、提供者和密码的引用:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
'passwords' => [
'admin' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
],
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
当然,这意味着我的管理员和用户存储在数据库中的不同表中,但它工作得非常好,没有任何问题,所以我完全同意。
解决方案:用 Session:forget('url.intended');
清除预期的 urlprotected function unauthenticated($request, AuthenticationException $exception)
{
// dd($exception);
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'learner':
$login = 'learner.login';
break;
default:
$login = 'login';
break;
}
Session::forget('url.intented');
return redirect()->route($login);
}