一、经过 Auth 中间件检查后跳转至登录页面

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

打开 auth 中间件文件:

// 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 是在捕捉到这个异常后进行进一步的操作。

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

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

  

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

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 键被创建的意义就是在登录成功后用来跳转的。

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

// 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() 方法:

// 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 中间件拦截的那个页面。

总结流程如下:

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

二、由不需认证的页面跳转至登录页面

也就是访问的页面是公开的,登录或者没登录的用户都能访问,在这个页面上点击登录按钮后进入登录页面。这种情况下,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 键的值,如果有值就会跳转到该页面。

(完)

最新文章

  1. Windows Server 2008 R2 DNS 服务器迁移
  2. Java集合 之 Queue集合
  3. 【转】Xcode7真机调试iOS应用程序
  4. ArrayList 练习
  5. WPF笔记(1.10 绘图)——Hello,WPF!
  6. JavaScript继承的实现
  7. rabbitMQ 在 windows 64位环境下无法启动(提示乱码)的解决方法
  8. ubuntu16.04下idea、webstorm等开发工具不能输入中文问题
  9. [转]IP地址介绍
  10. oracle undo redo 解析
  11. MySQL数据导入到Mongo
  12. Springboot 如何加密,以及利用Swagger2构建Restful API
  13. intent调用代码总结
  14. Day18 (二)反射
  15. CF1030A 【In Search of an Easy Problem】
  16. SQL Server 连接字符串和身份验证 学习
  17. ORM-老师信息系统
  18. java实现短连接
  19. 洛谷 P1074 靶形数独
  20. 51nod - 1188 - 最大公约数之和 V2 - 数论

热门文章

  1. HDU4183 Pahom on Water(来回走最大流,一个点只经过一次)
  2. DRF序列化和反序列化(二:ModelSerializer)
  3. python案例-判断素数
  4. PL/SQL Developer 快捷键
  5. str = @"abc ""def"" ghi """"jkl"""" mn";
  6. Go语言 - 结构体 | 方法
  7. Redis主从复制之哨兵模式(sentinel)
  8. 如何开发出优秀的APICloud应用
  9. OpenCV应用(4)雄迈相机网络取图
  10. Numpy | 13 位运算