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 鍵的值,若是有值就會跳轉到該頁面。

(完)

相關文章
相關標籤/搜索