Laravel 登录后重定向回原始目的地

222

这似乎是一个相当基础的流程,而且 Laravel 有许多好的解决方案来处理基本的事情,我觉得我可能遗漏了什么。

用户点击需要身份验证的链接。 Laravel 的 auth 过滤器启动并将用户路由到登录页面。 用户登录后,再次访问之前被“auth”过滤器拦截的原始页面。

有没有一种很好的方法可以知道他们最初想要进入哪个页面?由于 Laravel 拦截请求,我不知道它是否在某处记录以便用户登录后轻松路由。

如果没有,我很想听听你们中的一些人如何手动实现这一点。

26个回答

253

适用于 Laravel 5.3 及以上版本

请查看下面Scott的答案

适用于 Laravel 5 至 5.2 版本

简单来说,

在身份验证中间件上:

// redirect the user to "/login"
// and stores the url being accessed on session
if (Auth::guest()) {
    return redirect()->guest('login');
}
return $next($request);

在登录操作中:

// redirect the user back to the intended page
// or defaultpage if there isn't one
if (Auth::attempt(['email' => $email, 'password' => $password])) {
    return redirect()->intended('defaultpage');
}

Laravel 4(旧版)

在回答时,框架本身没有官方支持。现在您可以使用下面所述的方法:bgdrl指出的方法此方法:(我尝试更新他的答案,但似乎他不接受)

关于身份验证过滤器:

// redirect the user to "/login"
// and stores the url being accessed on session
Route::filter('auth', function() {
    if (Auth::guest()) {
        return Redirect::guest('login');
    }
});

在登录操作中:

// redirect the user back to the intended page
// or defaultpage if there isn't one
if (Auth::attempt(['email' => $email, 'password' => $password])) {
    return Redirect::intended('defaultpage');
}

对于 Laravel 3(甚至更早版本的答案)

您可以像这样实现它:

Route::filter('auth', function() {
    // If there's no user authenticated session
    if (Auth::guest()) {
        // Stores current url on session and redirect to login page
        Session::put('redirect', URL::full());
        return Redirect::to('/login');
    }
    if ($redirect = Session::get('redirect')) {
        Session::forget('redirect');
        return Redirect::to($redirect);
    }
});

// on controller
public function get_login()
{
    $this->layout->nest('content', 'auth.login'); 
}

public function post_login()
{
    $credentials = [
        'username' => Input::get('email'),
        'password' => Input::get('password')
    ];

    if (Auth::attempt($credentials)) {
        return Redirect::to('logged_in_homepage_here');
    }

    return Redirect::to('login')->with_input();
}

将重定向存储在会话中的好处是,即使用户输入错误的凭据或者没有帐户并且需要注册,它仍然可以持久化。
这还允许除了认证之外的任何其他东西在会话上设置重定向,并且它会自动工作。

2
我已经编辑了答案,解释了为什么这比flash更好。 - vFragosop
看起来不错,虽然我不太明白流程。用户进入/admin,auth过滤器抓取它,在会话中设置重定向URL并交给登录重定向处理。登录重定向到一个带有表单的页面。表单被提交,LoginController执行Auth:attempt。如果成功,我如何回到您列出的auth过滤器进行重定向?在成功的Auth:attempt之后,将第二个if语句(上面)放在LoginController中是否更好? - JOV
1
当Auth :: attempt()通过时,您可以简单地将用户重定向到默认页面(通常是他的主页)。该重定向将再次通过该过滤器,并在有一个原始请求的URL时将其重定向到原始请求的URL。否则,它将继续呈现他的主页。我会放一个登录操作的示例。 - vFragosop
如果你非常确定我的解决方案不起作用,我温和地请你提供一个更好的答案,恰当地解释你的选择以及为什么它不起作用。如果你不是那么确定,可以随意打开另一个问题,并附上你的代码,我会回答它。因为我更加确定你没有正确阅读我的先前评论或者甚至没有尝试过它。无论如何,这些评论已经太过了。 - vFragosop
1
在5.1版本中,它位于中间件RedirectIfAuthenticated.php中:如果($this->auth->check()) { return redirect('/privatepage'); } - Dave Driesmans
显示剩余13条评论

105

Laravel >= 5.3

在5.3中进行的认证更改使其实现变得更加容易,并且与5.2略有不同,因为Auth中间件已被移动到服务容器中。

修改新的中间件auth重定向器

/app/Http/Middleware/RedirectIfAuthenticated.php

稍微改变句柄函数的写法,使其看起来像这样:

public function handle($request, Closure $next, $guard = null)
{
    if (Auth::guard($guard)->check()) {
        return redirect()->intended('/home');
    }

    return $next($request);
}

简短概述

唯一的区别在于第四行;默认情况下它看起来像这样:

return redirect("/home");

Laravel >= 5.3 在检查身份验证保护时会自动保存最后一个“预期”的路由,因此它更改为:

return redirect()->intended('/home');

这告诉 Laravel 在登录前重定向到最后一个意图页面,否则默认跳转到 "/home" 或者你想要的任意页面。

关于 Laravel 5.2 和 5.3 之间的区别并没有太多相关资料,而在这个领域尤其如此。


5
对于 Laravel 6.4,这个方法不再起作用了...有什么想法吗? - alex toader
4
我会使用return redirect()->intended(RouteServiceProvider::HOME);将您的主页路径统一放在一个位置。 - Mateusz
但在此之前,Laravel会显示一个403错误页面而不采取任何行动。相反,如何自动重定向到登录页面,然后再到预期的页面呢? - Pathros
谢谢。确认它仍然适用于 Laravel 9。 - Imtiaz

29

我发现了这两种非常有效的方法,对你可能非常有帮助。

Redirect::guest();
Redirect::intended();

您可以将此过滤器应用于需要进行身份验证的路由。

Route::filter('auth', function()
{
    if (Auth::guest()) {
           return Redirect::guest('login');
    }
});

这个方法的基本思想是存储您尝试访问的页面,并将您重定向到登录页面。

当用户经过身份验证后,您可以调用

return Redirect::intended();

并且它会将您重定向到您最初尝试访问的页面。

这是一个很好的方法,尽管我通常使用下面的方法。

Redirect::back()

您可以查看这篇很棒的博客。


这比上面的解决方案好多了。上面的解决方案需要能够将闭包传递给登录函数,但我在4.1中无法做到。但这个方法更简单,而且可以直接使用。 - user2662680
但在此之前,Laravel会显示一个403错误页面而不采取任何行动。相反,如何自动重定向到登录页面,然后再到预期的页面呢? - Pathros

22
你可以使用 Redirect::intended 函数。它将重定向用户到他们在经过身份验证过滤器之前尝试访问的URL。如果预期的目标不可用,该方法可以提供一个备用的URI。
在登录/注册后:
return Redirect::intended('defaultpageafterlogin');

但在此之前,Laravel 会显示一个 403 错误页面而不执行任何操作。相反,如何自动重定向到登录页面,然后再跳转到所需访问的页面? - Pathros

14

将您的LoginControllers构造函数更改为:

public function __construct()
    {
        session(['url.intended' => url()->previous()]);
        $this->redirectTo = session()->get('url.intended');

        $this->middleware('guest')->except('logout');
    }

它会将您重定向回登录页面之前的页面(向后2页)。


唯一能为我工作的。这意味着我在其他地方有另一个重定向,但谁知道在哪里。 - Arthur Tarasov
2
在所有上述解决方案中,这个对于我的 Laravel 7 版本有效。太棒了伙计! - Shaan

12

我在我的语言选择器代码中使用了这个功能一段时间了。只要你只需要回到上一页,它就能正常工作:

return Redirect::to(URL::previous());

虽然它不是最强大的解决方案,但易于使用且可以帮助解决一些难题。 :)


5
是的,previous() 方法可以正常工作。但是,如果您的第一次登录尝试失败(因此“登录失败”页面成为您的上一页),而第二次登录尝试成功,则会再次重定向到登录页面(该页面可能会将您重定向到主页)。 - Shriganesh Shintre
太棒了伙计!它帮助我节省了时间。 - Kapil Yadav

10

适用于 Laravel 8

下面的方法对于 Laravel 8 对我很有效。

基于控制器的方法

/app/Http/Controllers/Auth/AuthenticatedSessionController.php

登录前

预期的 URL 将在创建会话时存储:

/**
 * Display the login view.
 *
 * @return \Illuminate\View\View
 */
public function create()
{
    session(['url.intended' => url()->previous()]);
    return view('auth.login');
}

登录后

登录成功后,如果会话中有预定的URL,则重定向到该URL,否则重定向到默认URL:

/**
 * Handle an incoming authentication request.
 *
 * @param  \App\Http\Requests\Auth\LoginRequest  $request
 * @return \Illuminate\Http\RedirectResponse
 */
public function store(LoginRequest $request)
{
    $request->authenticate();

    //in case intended url is available
    if (session()->has('url.intended')) {
        $redirectTo = session()->get('url.intended');
        session()->forget('url.intended');
    }

    $request->session()->regenerate();

    if ($redirectTo) {
        return redirect($redirectTo);
    }
    return redirect(RouteServiceProvider::HOME);
}

8
return Redirect::intended('/');

这将会把你重定向到你的项目默认页面,也就是起始页。

6

对于 Laravel 5.*,请尝试以下方法。

return redirect()->intended('/');

或者
return Redirect::intended('/');

5

Laravel 3

我稍微调整了您(Vinícius Fragoso Pinheiro)的代码,并将以下内容放置在filters.php中。

Route::filter('auth', function()
{
    // If there's no user authenticated session
    if (Auth::guest()) {
        // Flash current url to session and redirect to login page
        Session::flash('redirect', URL::full());
        return Redirect::guest('login');
    }
});

然后在我的 AuthController.php 文件中:

// Try to log the user in.
if (Auth::attempt($userdata)) {

    if ($redirect = Session::get('redirect')) {
        return Redirect::to($redirect);
    } else {
        // Redirect to homepage
        return Redirect::to('your_default_logged_in_page')->with('success', 'You have logged in successfully');
    }
} else {
    // Reflash the session data in case we are in the middle of a redirect 
    Session::reflash('redirect');

    // Redirect to the login page.
    return Redirect::to('login')->withErrors(['password' => 'Password invalid'])->withInput(Input::except('password'));
}

请注意,如果出现身份验证问题,会重新引用'redirect'会话数据。这在任何登录问题期间保持重定向不变,但是如果用户在任何时候点击离开,下一个登录过程不受会话数据干扰。

您还需要在AuthController中显示登录表单的位置刷新数据,否则链路将被中断:

public function showLogin()
{
    // Reflash the session data in case we are in the middle of a redirect 
    Session::reflash('redirect');

    // Show the login page
    return View::make('auth/login');
}

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