前言

Laravel有一个神器:

php artisan make:auth

能够快速的帮我们完成一套注册和登录的认证机制,但是这套机制具体的是怎么跑起来的呢?我们不妨来一起看看他的源码。不过在这篇文章中,我只会阐述大致的流程,至于一些具体的细节,比如他的登录次数限制是怎么完成的之类的不妨自己去寻找答案。

源码解读系列,有兴趣的小伙伴可以点个star,我会持续更新各个部分的解读,也是和大家一起进步的一个过程,如有写的不对的地方还望指出。

过程

路由

当我们执行完命令之后,我们会发现,在routes/web.php中多了这样一行代码:

Auth::routes();

结合我们在前面讲到的Facades,我们会执行Facades/Auth.phproutes方法:

public static function routes()
{
static::$app->make('router')->auth();
}

$app->make('router')会返回一个Routing/Router.php对象的实例,而他的auth方法是:

public function auth()
{
// Authentication Routes...
$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
$this->post('login', 'Auth\LoginController@login');
$this->post('logout', 'Auth\LoginController@logout')->name('logout'); // Registration Routes...
$this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
$this->post('register', 'Auth\RegisterController@register'); // Password Reset Routes...
$this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
$this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
$this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
$this->post('password/reset', 'Auth\ResetPasswordController@reset');
}

而这里的getpost方法,其实也就是我们通过Route::get等最终会调用的方法。

注册

我们直接看表单提交的方法:

        $this->post('register', 'Auth\RegisterController@register');
//RegisterController.php
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/ use RegistersUsers; /**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = '/home'; /**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
} /**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
]);
} /**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
}

里面使用到了RegistersUsers这个trait,里面就有我们需要的register方法:

public function register(Request $request)
{
$this->validator($request->all())->validate(); event(new Registered($user = $this->create($request->all()))); // 默认情况下,$this->guard()会返回一个`SessionGuard`的对象
$this->guard()->login($user); return $this->registered($request, $user)
?: redirect($this->redirectPath());
} protected function guard()
{
return Auth::guard();
}

其中最核心的部分就是:

$this->guard()->login($user);

$this->guard()在默认配置下会返回一个SessionGuard的对象,具体是这样实现的:

前面我们有讲过,当我们执行Facades下一个不存在的方法时,我们会调用Facade.php__callStatic方法,这个方法会获取当前对象的getFacadeAccessor方法而返回一个对应的对象并调用他所需要调用的方法,这个详细过程在我的第三篇中都有所阐述。

auth的别名绑定,是在我们初始化的过程中绑定的,具体可以看我写的第一篇,所以,这里我们会调用AuthManager这个对象:

 public function guard($name = null)
{
$name = $name ?: $this->getDefaultDriver(); return isset($this->guards[$name])
? $this->guards[$name]
: $this->guards[$name] = $this->resolve($name);
} public function getDefaultDriver()
{
return $this->app['config']['auth.defaults.guard'];
} protected function resolve($name)
{
$config = $this->getConfig($name); if (is_null($config)) {
throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
} if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($name, $config);
} $driverMethod = 'create'.ucfirst($config['driver']).'Driver'; if (method_exists($this, $driverMethod)) {
return $this->{$driverMethod}($name, $config);
} throw new InvalidArgumentException("Auth guard driver [{$name}] is not defined.");
}
//config/auth.php

'defaults' => [
'guard' => 'web',
'passwords' => 'users',
], 'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
], 'api' => [
'driver' => 'token',
'provider' => 'users',
],
],

通过调用AuthManager可以拼接得出,最终他会调用一个createSessionDriver方法:

public function createSessionDriver($name, $config)
{
$provider = $this->createUserProvider($config['provider']); $guard = new SessionGuard($name, $provider, $this->app['session.store']); if (method_exists($guard, 'setCookieJar')) {
$guard->setCookieJar($this->app['cookie']);
} if (method_exists($guard, 'setDispatcher')) {
$guard->setDispatcher($this->app['events']);
} if (method_exists($guard, 'setRequest')) {
$guard->setRequest($this->app->refresh('request', $guard, 'setRequest'));
} return $guard;
}

所以最终是调用了SessionGuardlogin方法来完成session部分的功能。

登录

展示表单的部分就不赘述了,这里我们直接看:

$this->post('login', 'Auth\LoginController@login');
//LoginController.php
class LoginController extends Controller
{
use AuthenticatesUsers; /**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = '/home'; /**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}

他使用到了一个AuthenticatesUserstrait,里面有一个login方法,也就是我们要使用到的login了:

public function login(Request $request)
{
$this->validateLogin($request); if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request); return $this->sendLockoutResponse($request);
} if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
} $this->incrementLoginAttempts($request); return $this->sendFailedLoginResponse($request);
}

其实大部分和register的部分差不多,核心部分还是在于SessionGuard对象的获取,这里就不过多赘述了,不过值得一提的是,像Auth::check()等很多方法的使用,其实也会通过SessionGuard来完成,主要是通过:

public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}
public function check()
{
return ! is_null($this->user());
}

来得以完成调度。

Laravel 源码解读系列第四篇-Auth 机制的更多相关文章

  1. Alamofire源码解读系列(四)之参数编码(ParameterEncoding)

    本篇讲解参数编码的内容 前言 我们在开发中发的每一个请求都是通过URLRequest来进行封装的,可以通过一个URL生成URLRequest.那么如果我有一个参数字典,这个参数字典又是如何从客户端传递 ...

  2. Alamofire源码解读系列(五)之结果封装(Result)

    本篇讲解Result的封装 前言 有时候,我们会根据现实中的事物来对程序中的某个业务关系进行抽象,这句话很难理解.在Alamofire中,使用Response来描述请求后的结果.我们都知道Alamof ...

  3. Alamofire源码解读系列(六)之Task代理(TaskDelegate)

    本篇介绍Task代理(TaskDelegate.swift) 前言 我相信可能有80%的同学使用AFNetworking或者Alamofire处理网络事件,并且这两个框架都提供了丰富的功能,我也相信很 ...

  4. Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager)

    Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager) 本篇主要讲解iOS开发中的网络监控 前言 在开发中,有时候我们需要获取这些信息: 手机是否联网 ...

  5. Alamofire源码解读系列(八)之安全策略(ServerTrustPolicy)

    本篇主要讲解Alamofire中安全验证代码 前言 作为开发人员,理解HTTPS的原理和应用算是一项基本技能.HTTPS目前来说是非常安全的,但仍然有大量的公司还在使用HTTP.其实HTTPS也并不是 ...

  6. Alamofire源码解读系列(九)之响应封装(Response)

    本篇主要带来Alamofire中Response的解读 前言 在每篇文章的前言部分,我都会把我认为的本篇最重要的内容提前讲一下.我更想同大家分享这些顶级框架在设计和编码层次究竟有哪些过人的地方?当然, ...

  7. Alamofire源码解读系列(十)之序列化(ResponseSerialization)

    本篇主要讲解Alamofire中如何把服务器返回的数据序列化 前言 和前边的文章不同, 在这一篇中,我想从程序的设计层次上解读ResponseSerialization这个文件.更直观的去探讨该功能是 ...

  8. Alamofire源码解读系列(十一)之多表单(MultipartFormData)

    本篇讲解跟上传数据相关的多表单 前言 我相信应该有不少的开发者不明白多表单是怎么一回事,然而事实上,多表单确实很简单.试想一下,如果有多个不同类型的文件(png/txt/mp3/pdf等等)需要上传给 ...

  9. Alamofire源码解读系列(十二)之时间轴(Timeline)

    本篇带来Alamofire中关于Timeline的一些思路 前言 Timeline翻译后的意思是时间轴,可以表示一个事件从开始到结束的时间节点.时间轴的概念能够应用在很多地方,比如说微博的主页就是一个 ...

随机推荐

  1. JMeter安装和简介

    1.Apache jmeter 是一个100%的纯java桌面应用,用于压力测试和性能测量.它最初被设计用于Web应用测试但后来扩展到其他测试领域,可以用于对静态的和动态的资源(文件,Servlet, ...

  2. Java中几种常量池的区分

    转载自:https://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/ 在java的内存分配中,经常听到很多关于常量 ...

  3. ffmpeg音频播放代码示例-avcodec_decode_audio4

    一.概述 最近在学习ffmpeg解码的内容,参考了官方的教程http://dranger.com/ffmpeg/tutorial03.html,结果发现这个音频解码的教程有点问题.参考了各种博客,并同 ...

  4. InvalidateRect和UpdateWindow

    The UpdateWindow function updates the client area of the specified window by sending a WM_PAINT mess ...

  5. 浅谈服务器对SEO的影响,该如何选择服务器?

    对于SEO,很多人想的都是怎么做好网站的内部优化,做好外部推广.其实SEO没什么技术含量,到网上搜别人的心得看,千篇一律,都是翻来覆去的说一样的东西,就像吃不同人做的馒头,吃来吃去就是一个味道.笔者经 ...

  6. [2017-08-16]ABP系列——QuickStartB:正确理解Abp解决方案的代码组织方式、分层和命名空间

    本系列目录:Abp介绍和经验分享-目录 介绍ABP的文章,大多会提到ABP框架吸收了很多最佳实践,比如: 1.N层 (复用一下上篇的图) 展现层(Personball.Demo.Web):asp.ne ...

  7. django全文检索

    -------------------linux下配置操作1.在虚拟环境中依次安装包 1.pip install django-haystack haystack:django的一个包,可以方便地对m ...

  8. SVG图案

    前面的话 给SVG元素应用填充和描边,除了使用纯色和渐变外,还可以使用图案.本文将详细介绍SVG图案 概述 <pattern>可以实现重复的效果,在canvas中被翻译为模式,而在SVG中 ...

  9. G1垃圾收集器和CMS垃圾收集器 (http://mm.fancymore.com/reading/G1-CMS%E5%9E%83%E5%9C%BE%E7%AE%97%E6%B3%95.html#toc_8)

    参考来源 JVM 体系架构 堆/栈的内存分配 静态和非静态方法的内存分配 CMS 回收算法 应用场景 CMS 垃圾收集阶段划分(Collection Phases) CMS什么时候启动 CMS缺点 G ...

  10. Netty自娱自乐之协议栈设计

    ---恢复内容开始--- 俺工作已经一年又6个月了,想想过的真快,每天写业务,写业务,写业务.......然后就是祈祷着,这次上线不要出现线上bug.继续这每天无聊的增删改查,学习学习一下自己感兴趣的 ...