Laravel 登陆后跳转回登陆前浏览的页面

1、通过 Auth 中间件检查后跳转至登陆页面

也就是没有经过 auth 中间件的认证检查,被 auth 中间件拦截后跳转至登陆页面。这种状况下,Laravel 默认会在用户登陆成功后自动跳转回登陆前浏览的页面。auth 中间件是怎么作到的?php

打开 auth 中间件文件:laravel

// vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php

protected function authenticate(array $guards)
{
    if (empty($guards)) {
          return $this->auth->authenticate();
    }

    foreach ($guards as $guard) {
        if ($this->auth->guard($guard)->check()) {
          return $this->auth->shouldUse($guard);
        }
    }

    throw new AuthenticationException('Unauthenticated.', $guards);
}

  

auth 中间件经过 authenticate() 方法检查用户是否通过了认证,若是没有通过认证就抛出一个异常。其中并无跳转至登陆页面的操做,也就是说 Laravel 是在捕捉到这个异常后进行进一步的操做。json

Laravel 在异常处理类 Illuminate\Foundation\Exceptions\Handler 中处理这个 AuthenticationException 异常。因为在异常处理类的 $internalDontReport 属性中包含了该异常,因此 AuthenticationException 异常不须要报告或者写入日志,只须要经过 render() 方法处理为一个响应。在 render() 方法中会调用 unauthenticated() 方法来处理 AuthenticationException 异常session

protected function unauthenticated($request, AuthenticationException $exception)
{
      return $request->expectsJson()
        ? response()->json(['message' => $exception->getMessage()], 401)
        : redirect()->guest(route('login'));
}

  

在 unauthenticated() 方法中首先检查请求是否须要 Json 响应,若是不须要就会执行 redirect()->guest() 方法app

public function guest($path, $status = 302, $headers = [], $secure = null)
{
    $this->session->put('url.intended', $this->generator->full());

    return $this->to($path, $status, $headers, $secure);
}

  

在重定向的 guest() 方法中,先将用户访问(但没经过认证)的页面地址存入 Session 的 url.intended 键上,而后重定向到登陆界面。这个 Session 的 url.intended 键被建立的意义就是在登陆成功后用来跳转的。this

打开登陆控制器 Auth\LoginController.php 文件中 LoginController 继承的 AuthenticatesUsers 这个 Trait。在这个 Trait 中,login() 方法处理登陆请求,验证成功后调用 sendLoginResponse() 方法返回响应:url

// vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php

protected function sendLoginResponse(Request $request)
{
    $request->session()->regenerate();

    $this->clearLoginAttempts($request);

    return $this->authenticated($request, $this->guard()->user()) 
      ?: redirect()->intended($this->redirectPath());
}

  

在该方法最后的 return 中能够看到:若是 authenticated() 方法返回值不为真,则执行 redirect()->intended() 方法。而 authenticated() 方法默认为空,因此必然会执行 redirect()->intended() 方法spa

// vendor/laravel/framework/src/Illuminate/Routing/Redirector.php

public function intended($default = '/', $status = 302, $headers = [], $secure = null)
{
    $path = $this->session->pull('url.intended', $default);

    return $this->to($path, $status, $headers, $secure);
}

  

在重定向的 intended() 方法中会检查 Seesion url.intended 键的值。若是有值,就会跳转到该地址,也就是访问但被 Auth 中间件拦截的那个页面。日志

总结流程以下:code

访问须要认证的页面 -> 被 Auth 中间件拦截后抛出异常 -> 处理异常:在 Session 中存入要访问的页面地址,而后跳转至登陆页面 -> 登陆成功后从 Session 中取出先前存入的页面地址,并跳转至该地址。

2、由不需认证的页面跳转至登陆页面

也就是访问的页面是公开的,登陆或者没登陆的用户都能访问,在这个页面上点击登陆按钮后进入登陆页面。这种状况下,Laravel 默认返回的是域名的根地址。只要搞明白了第一种状况中 Lararvel 的处理流程,这种状况处理起来很是简单:

只需在 Auth\LoginController.php 控制器中重写其继承的 AuthenticatesUsers 这个 Trait 中的 showLoginForm() 方法便可:

// app/Http/Controllers/Auth/LoginController.php
use AuthenticatesUsers;

// 打开登陆页面
public function showLoginForm()
{
    session(['url.intended'=>url()->previous()]);

    return view('auth.login');
}

  

只需在原有的 showLoginForm() 方法中添加一行便可!这个操做的关键就是打开登陆页面时,将上一个浏览的页面地址存入 Session 的 url.intended 键。

因为登陆步骤和第一种状况同样,因此 Laravel 会在登陆成功后检查 Session url.intended 键的值,若是有值就会跳转到该页面。

(完)

相关文章
相关标签/搜索