在Laravel内置的身份验证中,如果已经验证成功,则进行重定向的逻辑是什么?

14

这个问题之前已经被问过了,我相信我的代码是正确的,但是我得到了奇怪的结果。

我需要根据一些数据库值在登录后将用户重定向到不同的路由。我认为我只需要将逻辑放在app/Http/Middleware/RedirectIfAuthenticated.php文件中的handle方法中即可完成。目前我的方法看起来像这样:

public function handle($request, Closure $next)
{

    if ($this->auth->check()) {
        if($this->auth->user()->sign_up_complete == 1){
            return redirect('/');
        } else {
            if($this->auth->user()->step_one_complete == 0){
                return redirect('/register/step-1');
            } elseif($this->auth->user()->step_two_complete == 0){
                return redirect('/register/step-2');
            } else {
                return redirect('/');
            }
        }
    }

    return $next($request);
}

这种方法不起作用,在登录后用户被重定向到/home。我尝试将dd($this->auth->user())放在$this->auth->check()条件的内部,但它从未运行过。如果我将其放在该检查之外,则会在每个请求上运行。看起来$this->auth->check()从未运行。

我的问题是:如果不是在这里,那么这个逻辑应该放在哪里?

我还从AuthController.php控制器中删除了protected $redirectTo = '/account';


那个 check() 函数在哪里? - Narendrasingh Sisodia
2
RedirectIfAuthenticated 似乎是一个 guest 中间件。此外,在 Illuminate\Foundation\Auth\RedirectUsers 中,如果您没有设置 $redirectTo,则会重定向到 /home。但在这种情况下并不重要。您尝试过使用 Authenticate 中间件吗?将逻辑移动到 $this->auth->guest() 检查之后,然后再写您的内容。这个中间件将在用户需要进行身份验证时每次运行。因此,基本检查将在未经身份验证时将它们重定向。如果已经过身份验证,它将继续进行您的检查。 - Iamzozo
@Iamzozo 我不确定我理解了。那似乎完全是为其他事情而设计的? - Mike
看起来,如果我使用guest中间件,它会运行RedirectIfAuthenticated。但是auth中间件不会运行RedirectIfAuthenticated,而是运行Authenticate。因为您想在登录后检查用户是否完成了所有步骤,所以所有受保护的页面都将运行Authenticate中间件,因此运行您的检查。如果您想从不需要的页面重定向用户,则使用guest中间件。例如,如果用户已登录,则不希望显示登录表单。在这里,您使用guest中间件,它将调用RedirectIfAuthenticated并在已经登录时重定向到主页。 - Iamzozo
@mikemike,你在控制器中编写了中间件的代码吗? - smartrahat
你找到了合适的答案吗?请接受它。 - Mark Walet
6个回答

12

高层次回答: RedirectIfAuthenticated 的目的是防止已认证的用户到达登录或注册路由/视图,因为他们已经登录了。

测试:将登录视图添加为书签。然后登录。关闭浏览器或窗口。打开登录书签。您将直接进入用户主页或在RedirectIfAuthenticated中指定的任何位置。

对于LoginController的目的,创建一个redirecTo()方法,这就是redirectPath()方法查找是否自定义重定向的地方。

// example
public function redirectTo()
{
    switch (auth()->user()->role) {
        case 'foo':
            return route('foo.home');

        case 'bar':
            return route('bar.home');

        default:
            auth()->logout();
            return route('web.welcome');
    }
}

9

您没有正确使用中间件。每当您已登录并发送请求时,此代码片段将触发。

要更改登录后的重定向位置,您可以在AuthController中覆盖redirectPath()方法。(您可以在vendor/laravel/framework/src/Illuminate/Foundation/Auth/RedirectsUsers.php中找到原始方法)

这将类似于以下内容:

...

public class AuthController extends Controller {

    ...

    public function redirectPath()
    {
        if(Auth::user()->sign_up_complete == 1) {
            return '/';
        } else {
            if(Auth::user()->step_one_complete == 0) {
                return '/register/step-1';
            } elseif(Auth::user()->step_two_complete == 0) {
                return '/register/step-2';
            } else {
                return '/';
            }
        }
    }


    // The rest of the class implementation.

}

注意:我已经用门面模式的替代方法(Auth::)替换了$this->auth() 方法。只是因为我不确定AuthController是否有auth() 方法。

4
为了理解为什么您的路由逻辑从未被触发,您应该查看 app/Http/Kernel.php 中注册的 RedirectIfAuthenticated 中间件:
protected $routeMiddleware = [
    ...
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    ...
];

这意味着如果用户导航到不受“guest”路由中间件保护的路由,则请求永远不会通过RedirectIfAuthenticated类,从而完全错过您的逻辑。
您可以在路由文件中将guest中间件添加到注册路由中,以强制路由通过您的代码,如下所示:
Route::get('/register/step-1', '<YOUR CONTROLLER METHOD>')->middleware('guest');

但是,由于你说用户已经登录(不是访客),所以你应该按照其他答案建议移动代码。

我只是添加了这个答案,因为在评论区无法澄清。


3
解决方案在Mark Walet的回答里,但需要进行一些小的更正。返回值应该是一个字符串:
public class AuthController extends Controller {

    ...

    public function redirectPath()
    {
        if(Auth::user()->sign_up_complete == 1) {
            return '/';
        } else {
            if(Auth::user()->step_one_complete == 0) {
                return '/register/step-1';
            } elseif(Auth::user()->step_two_complete == 0) {
                return '/register/step-2';
            } else {
                return '/';
            }
        }
    }


    // The rest of the class implementation.

}

1
这应该是你在我的解决方案中发表评论时说的话。然后我收到了通知并立即进行了更新。 - Mark Walet
哦,好的,抱歉。下次会这样做。 - Dmitry

2

我认为只需设置一个自定义的中间件类,根据数据库值验证请求就可以轻松实现这一点。我使用此方法来排除没有正确角色的用户。

角色在我的用户表中定义,只有管理员角色的用户才能访问系统。

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\MessageBag;

class RolesMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // If a user is authenticated
        if(\Auth::user() != null)
        {
            // If the user doesn't have the correct role
            if(\Auth::user()->role != 'administrator')
            {
                // logout the user
                \Auth::logout();

                // create a new MessageBag
                $messageBag = new MessageBag;

                // add a message
                $messageBag->add('not_allowed', 'You are not allowed to login, because you do not have the right role!');

                // redirect back to the previous page with errors
                return \Redirect::to('login')->withErrors($messageBag);
            }
        }

        return $next($request);

    }
}


2

你不能修改Laravel的核心文件,你需要做的是将以下代码添加到Auth\AuthController中

protected $redirectPath = '/dashboard';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接