Laravel 源码解读系列第四篇-Auth 机制
前言
Laravel有一个神器:
php artisan make:auth
能够快速的帮我们完成一套注册和登录的认证机制,但是这套机制具体的是怎么跑起来的呢?我们不妨来一起看看他的源码。不过在这篇文章中,我只会阐述大致的流程,至于一些具体的细节,比如他的登录次数限制是怎么完成的之类的不妨自己去寻找答案。
源码解读系列,有兴趣的小伙伴可以点个star,我会持续更新各个部分的解读,也是和大家一起进步的一个过程,如有写的不对的地方还望指出。
过程
路由
当我们执行完命令之后,我们会发现,在routes/web.php中多了这样一行代码:
Auth::routes();
结合我们在前面讲到的Facades,我们会执行Facades/Auth.php的routes方法:
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');
}
而这里的get和post方法,其实也就是我们通过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;
}
所以最终是调用了SessionGuard的login方法来完成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 机制的更多相关文章
- Alamofire源码解读系列(四)之参数编码(ParameterEncoding)
本篇讲解参数编码的内容 前言 我们在开发中发的每一个请求都是通过URLRequest来进行封装的,可以通过一个URL生成URLRequest.那么如果我有一个参数字典,这个参数字典又是如何从客户端传递 ...
- Alamofire源码解读系列(五)之结果封装(Result)
本篇讲解Result的封装 前言 有时候,我们会根据现实中的事物来对程序中的某个业务关系进行抽象,这句话很难理解.在Alamofire中,使用Response来描述请求后的结果.我们都知道Alamof ...
- Alamofire源码解读系列(六)之Task代理(TaskDelegate)
本篇介绍Task代理(TaskDelegate.swift) 前言 我相信可能有80%的同学使用AFNetworking或者Alamofire处理网络事件,并且这两个框架都提供了丰富的功能,我也相信很 ...
- Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager)
Alamofire源码解读系列(七)之网络监控(NetworkReachabilityManager) 本篇主要讲解iOS开发中的网络监控 前言 在开发中,有时候我们需要获取这些信息: 手机是否联网 ...
- Alamofire源码解读系列(八)之安全策略(ServerTrustPolicy)
本篇主要讲解Alamofire中安全验证代码 前言 作为开发人员,理解HTTPS的原理和应用算是一项基本技能.HTTPS目前来说是非常安全的,但仍然有大量的公司还在使用HTTP.其实HTTPS也并不是 ...
- Alamofire源码解读系列(九)之响应封装(Response)
本篇主要带来Alamofire中Response的解读 前言 在每篇文章的前言部分,我都会把我认为的本篇最重要的内容提前讲一下.我更想同大家分享这些顶级框架在设计和编码层次究竟有哪些过人的地方?当然, ...
- Alamofire源码解读系列(十)之序列化(ResponseSerialization)
本篇主要讲解Alamofire中如何把服务器返回的数据序列化 前言 和前边的文章不同, 在这一篇中,我想从程序的设计层次上解读ResponseSerialization这个文件.更直观的去探讨该功能是 ...
- Alamofire源码解读系列(十一)之多表单(MultipartFormData)
本篇讲解跟上传数据相关的多表单 前言 我相信应该有不少的开发者不明白多表单是怎么一回事,然而事实上,多表单确实很简单.试想一下,如果有多个不同类型的文件(png/txt/mp3/pdf等等)需要上传给 ...
- Alamofire源码解读系列(十二)之时间轴(Timeline)
本篇带来Alamofire中关于Timeline的一些思路 前言 Timeline翻译后的意思是时间轴,可以表示一个事件从开始到结束的时间节点.时间轴的概念能够应用在很多地方,比如说微博的主页就是一个 ...
随机推荐
- 一个基于ES6+webpack的vue小demo
上一篇文章<一个基于ES5的vue小demo>我们讲了如何用ES5,vue-router做一个小demo,接下来我们来把它变成基于ES6+webpack的demo. 一.环境搭建及代码转换 ...
- Centos定时任务
安装crontab:yum install crontabs说明:/sbin/service crond start //启动服务/sbin/service crond stop //关闭服务/sbi ...
- 【Hadoop】集群配置要点
1.SSH免密码登录 1.1生成公钥,一直enter,直到完成 dream361@master:~$ ssh-keygen -t rsa 1.2传送公钥 dream361@master:~$ scp ...
- 一起来学linux:用户与用户组
linux的文件属性以及管理方法和windows是完全不同的,所以学习linux首先来了解下用户以及文件权限是怎么回事 p { margin-bottom: 0.25cm; line-height: ...
- Composer简介及使用实例
1.PHP-FIG 官网:http://www.php-fig.org/ php编码规范: 本文档是PHP互操作性框架制定小组(PHP-FIG :PHP Framework Interoperabil ...
- Django 学习笔记(六)MySQL配置
环境:Ubuntu16.4 工具:Python3.5 一.安装MySQL数据库 终端命令: sudo apt-get install mysql-server sudo apt-get install ...
- Linux 查看进程
1.ps 显示进程信息,参数可省略 -aux 以BSD风格显示进程常用 -efH 以SystemV风格显示进程 -e , -A 显示所有进程 a 显示终端上所有用户的进程 x 显示无终端进程 u显示详 ...
- ASP.NET Core MVC I/O编程模型
1. ASP.NET Core MVC I/O编程模型 1.1. I/O编程模型浅析 1.2. 同步阻塞I/O 1.3. 同步非阻塞I/O 1.4. 异步I/O 1.5. 总结 1.1. I/O编程模 ...
- pycharm远程linux开发和调试代码
pycharm是一个非常强大的python开发工具,现在很多代码最终在线上跑的环境都是linux,而开发环境可能还是windows下开发,这就需要经常在linux上进行调试,或者在linux对代码进行 ...
- 阿里云centos下安装nginx、jdk、tomcat、绑定域名、解析域名
1.ESC后安全设置(管理控制台->本实例安全组->配置规则->添加安全组规则->3306.80端口配置) 2.nginx 安装,首先安装三大件 PCRE.zlib.ope ...