1. 生成相关文件和配置

快速生成命令

php artisan make:auth

运行后,使用git查看有哪些文件变化

$ git status
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: routes/web.php
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# app/Http/Controllers/HomeController.php
# resources/views/auth/
# resources/views/home.blade.php
# resources/views/layouts/
no changes added to commit (use "git add" and/or "git commit -a")

2. 分析路由文件

查看下路由文件,发现多了两条路由信息

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/ Route::get('/', function () {
return view('welcome');
}); //以下为新加的路由
Auth::routes(); Route::get('/home', 'HomeController@index')->name('home');

分析下Auth::routes()做了什么事

定位到Auth这个Facades,config/app.php中的aliases中有一条

'aliases' => [
'Auth' => Illuminate\Support\Facades\Auth::class,
// ...其他
],

打开Illuminate\Support\Facades\Auth.php后看到有个routes()方法

    /**
* Register the typical authentication routes for an application.
*
* @return void
*/
public static function routes()
{
static::$app->make('router')->auth();
}

定位到Illuminate\Routing\route.php,有个auth()方法,这个就是我们route\web.php路由文件中Autu::routes()最后能生成的路由。

    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');
}

查看下生效的路由,和上面的对比下,相匹配

$ php artisan route:list
+--------+----------+------------------------+------------------+------------------------------------------------------------------------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+------------------------+------------------+------------------------------------------------------------------------+--------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/user | | Closure | api,auth:api |
| | GET|HEAD | home | home | App\Http\Controllers\HomeController@index | web,auth |
| | GET|HEAD | login | login | App\Http\Controllers\Auth\LoginController@showLoginForm | web,guest |
| | POST | login | | App\Http\Controllers\Auth\LoginController@login | web,guest |
| | POST | logout | logout | App\Http\Controllers\Auth\LoginController@logout | web |
| | POST | password/email | password.email | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail | web,guest |
| | GET|HEAD | password/reset | password.request | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest |
| | POST | password/reset | | App\Http\Controllers\Auth\ResetPasswordController@reset | web,guest |
| | GET|HEAD | password/reset/{token} | password.reset | App\Http\Controllers\Auth\ResetPasswordController@showResetForm | web,guest |
| | GET|HEAD | register | register | App\Http\Controllers\Auth\RegisterController@showRegistrationForm | web,guest |
| | POST | register | | App\Http\Controllers\Auth\RegisterController@register | web,guest |
+--------+----------+------------------------+------------------+------------------------------------------------------------------------+--------------+

3. 以登陆开始为例,分析auth到底是怎么工作的

3.1 分析登录文件

定位文件 app/Http/Controllers/Auth/LoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers; # 1. 登录控制器
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/ 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');
}
}

LoginController.php并没有登录方法,why?实际上这里使用了trait,如果你用过软删除应该记得

use SoftDeletes;

这里也是使用了trait

use AuthenticatesUsers;

打开Illuminate\Foundation\Auth\AuthenticatesUsers.php

<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException; trait AuthenticatesUsers
{
use RedirectsUsers, ThrottlesLogins; /**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*/
public function login(Request $request)
{
$this->validateLogin($request); // If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request); return $this->sendLockoutResponse($request);
} # 2. 这里调用了attemptLogin()
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
} // If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request); return $this->sendFailedLoginResponse($request);
} /**
* Attempt to log the user into the application.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function attemptLogin(Request $request)
{
# 3. 找到 guard()方法
# 这里的attemp()方法一会分析
return $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
} /**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
# 4. 访问了Auth门面的guard()方法
return Auth::guard();
} // ...其它方法暂时省略 }

到这里我们知道login方法的结果 : 先实例化Auth::guard()实例,最终返回了这个实例的attempt()方法

3.2 分析门面Auth。

以下使用config/auth.php的原始默认配置进行分析

根据config/app.php里面的服务提供器和Facades, 最终定位到 Illuminate\Auth\AuthManager.php


/**
* Attempt to get the guard from the local cache.
*
* @param string $name
* @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
*/
public function guard($name = null)
{
# 5. 获取看守器,如果guard()没有参数则使用默认设置
$name = $name ?: $this->getDefaultDriver(); # 7. $name= 'web' 定位到resolve()方法
return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
} /**
* Resolve the given guard.
*
* @param string $name
* @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
*
* @throws \InvalidArgumentException
*/
protected function resolve($name)
{
#8. 获取配置
$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);
} # 10 .$config = ['driver' => 'session','provider' => 'users',]
# 拼接创建看守器的方法名 这里默认是 createSessionDriver
$driverMethod = 'create'.ucfirst($config['driver']).'Driver'; if (method_exists($this, $driverMethod)) {
# 11. 访问createSessionDriver()
return $this->{$driverMethod}($name, $config);
} throw new InvalidArgumentException("Auth guard driver [{$name}] is not defined.");
} /**
* Call a custom driver creator.
*
* @param string $name
* @param array $config
* @return mixed
*/
protected function callCustomCreator($name, array $config)
{
return $this->customCreators[$config['driver']]($this->app, $name, $config);
} /**
* Create a session based authentication guard.
*
* @param string $name
* @param array $config
* @return \Illuminate\Auth\SessionGuard
*/
public function createSessionDriver($name, $config)
{
# $name = 'session'
# $cofnig['provider'] = 'users' # 12. createUserProvider不在此文件,定位到最上面有使用trait
# 通过这句 use CreatesUserProviders; 定位
# 查看下面的Illuminate\Auth\CreatesUserProviders.php文件
$provider = $this->createUserProvider($config['provider'] ?? null); $guard = new SessionGuard($name, $provider, $this->app['session.store']); # 18. 到这里我们知道
# $provide 是EloquentUserProvider实例
# $guard 是 SessionGuard实例
# 在回头看第3步,Auth::guard()->attempt()
# 接下来看下面Illuminate\Auth\SessionGuard.php中的attempt() // When using the remember me functionality of the authentication services we
// will need to be set the encryption instance of the guard, which allows
// secure, encrypted cookie values to get generated for those cookies.
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;
} /**
* Create a token based authentication guard.
*
* @param string $name
* @param array $config
* @return \Illuminate\Auth\TokenGuard
*/
public function createTokenDriver($name, $config)
{
// The token guard implements a basic API token based guard implementation
// that takes an API token field from the request and matches it to the
// user in the database or another persistence layer where users are.
$guard = new TokenGuard(
$this->createUserProvider($config['provider'] ?? null),
$this->app['request']
); $this->app->refresh('request', $guard, 'setRequest'); return $guard;
} /**
* Get the guard configuration.
*
* @param string $name
* @return array
*/
protected function getConfig($name)
{
# 9. $name = 'web'
# 读取config/auth.php 中的guards数组中的{$name}值,
# 对应 'web' => ['driver' => 'session','provider' => 'users',],
return $this->app['config']["auth.guards.{$name}"];
} /**
* Get the default authentication driver name.
*
* @return string
*/
public function getDefaultDriver()
{
# 6. 读取config/auth.php 中的default数组中的guard值,默认是web
return $this->app['config']['auth.defaults.guard'];
} /**
* Set the default guard driver the factory should serve.
*
* @param string $name
* @return void
*/
public function shouldUse($name)
{
$name = $name ?: $this->getDefaultDriver(); $this->setDefaultDriver($name); $this->userResolver = function ($name = null) {
return $this->guard($name)->user();
};
} /**
* Set the default authentication driver name.
*
* @param string $name
* @return void
*/
public function setDefaultDriver($name)
{
$this->app['config']['auth.defaults.guard'] = $name;
} /**
* Register a new callback based request guard.
*
* @param string $driver
* @param callable $callback
* @return $this
*/
public function viaRequest($driver, callable $callback)
{
return $this->extend($driver, function () use ($callback) {
$guard = new RequestGuard($callback, $this->app['request'], $this->createUserProvider()); $this->app->refresh('request', $guard, 'setRequest'); return $guard;
});
} /**
* Get the user resolver callback.
*
* @return \Closure
*/
public function userResolver()
{
return $this->userResolver;
} /**
* Set the callback to be used to resolve users.
*
* @param \Closure $userResolver
* @return $this
*/
public function resolveUsersUsing(Closure $userResolver)
{
$this->userResolver = $userResolver; return $this;
} /**
* Register a custom driver creator Closure.
*
* @param string $driver
* @param \Closure $callback
* @return $this
*/
public function extend($driver, Closure $callback)
{
$this->customCreators[$driver] = $callback; return $this;
} /**
* Register a custom provider creator Closure.
*
* @param string $name
* @param \Closure $callback
* @return $this
*/
public function provider($name, Closure $callback)
{
$this->customProviderCreators[$name] = $callback; return $this;
} /**
* Dynamically call the default driver instance.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}
}

Illuminate\Auth\CreatesUserProviders.php

<?php

namespace Illuminate\Auth;

use InvalidArgumentException;

trait CreatesUserProviders
{
/**
* The registered custom provider creators.
*
* @var array
*/
protected $customProviderCreators = []; /**
* Create the user provider implementation for the driver.
*
* @param string|null $provider
* @return \Illuminate\Contracts\Auth\UserProvider|null
*
* @throws \InvalidArgumentException
*/
public function createUserProvider($provider = null)
{
# $provider = 'users' # 13. 获取提供器的配置
if (is_null($config = $this->getProviderConfiguration($provider))) {
return;
} if (isset($this->customProviderCreators[$driver = ($config['driver'] ?? null)])) {
return call_user_func(
$this->customProviderCreators[$driver], $this->app, $config
);
} # 15. $config = ['driver' => 'eloquent','model' => App\User::class,]
# $driver ='eloquent'
switch ($driver) {
case 'database':
return $this->createDatabaseProvider($config);
case 'eloquent':
# 16. 调用createEloquentProvider方法
return $this->createEloquentProvider($config);
default:
throw new InvalidArgumentException(
"Authentication user provider [{$driver}] is not defined."
);
}
} /**
* Get the user provider configuration.
*
* @param string|null $provider
* @return array|null
*/
protected function getProviderConfiguration($provider)
{
# $provider = 'users' # 14. 读取config/auth.php 中的providers数组中的{$provider}值
# 最终对应 'users' => ['driver' => 'eloquent','model' => App\User::class,],
if ($provider = $provider ?: $this->getDefaultUserProvider()) {
return $this->app['config']['auth.providers.'.$provider];
}
} /**
* Create an instance of the database user provider.
*
* @param array $config
* @return \Illuminate\Auth\DatabaseUserProvider
*/
protected function createDatabaseProvider($config)
{
$connection = $this->app['db']->connection(); return new DatabaseUserProvider($connection, $this->app['hash'], $config['table']);
} /**
* Create an instance of the Eloquent user provider.
*
* @param array $config
* @return \Illuminate\Auth\EloquentUserProvider
*/
protected function createEloquentProvider($config)
{
# 17. 实例化EloquentUserProvider,
# 记住提供器最终得到了EloquentUserProvider实例
# 返回 12
return new EloquentUserProvider($this->app['hash'], $config['model']);
} /**
* Get the default user provider name.
*
* @return string
*/
public function getDefaultUserProvider()
{
return $this->app['config']['auth.defaults.provider'];
}
}

Illuminate\Auth\SessionGuard.php 摘取主要涉及方法

    public function attempt(array $credentials = [], $remember = false)
{
$this->fireAttemptEvent($credentials, $remember); $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials); // If an implementation of UserInterface was returned, we'll ask the provider
// to validate the user against the given credentials, and if they are in
// fact valid we'll log the users into the application and return true.
if ($this->hasValidCredentials($user, $credentials)) {
# 19. 调用hasValidCredentials()
# 22. 如果返回真 定位到login()方法
$this->login($user, $remember); return true;
} // If the authentication attempt fails we will fire an event so that the user
// may be notified of any suspicious attempts to access their account from
// an unrecognized user. A developer may listen to this event as needed.
$this->fireFailedEvent($user, $credentials); return false;
} /**
* Determine if the user matches the credentials.
*
* @param mixed $user
* @param array $credentials
* @return bool
*/
protected function hasValidCredentials($user, $credentials)
{
# 20. 我们已经分析过$this->provider,默认得到的是EloquentUserProvider实例
# 查看下面文件 Illuminate\Auth\EloquentUserProvider.php
return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
} /**
* Log a user into the application.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param bool $remember
* @return void
*/
public function login(AuthenticatableContract $user, $remember = false)
{
# 23. 登录成功,存储session等操作。。。分析到此结束
$this->updateSession($user->getAuthIdentifier()); // If the user should be permanently "remembered" by the application we will
// queue a permanent cookie that contains the encrypted copy of the user
// identifier. We will then decrypt this later to retrieve the users.
if ($remember) {
$this->ensureRememberTokenIsSet($user); $this->queueRecallerCookie($user);
} // If we have an event dispatcher instance set we will fire an event so that
// any listeners will hook into the authentication events and run actions
// based on the login and logout events fired from the guard instances.
$this->fireLoginEvent($user, $remember); $this->setUser($user);
}

Illuminate\Auth\EloquentUserProvider.php 摘取主要涉及方法

    /**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(UserContract $user, array $credentials)
{
# 21. 最终这里进行了用户的验证,验证通过返回true,不通过返回false
$plain = $credentials['password']; return $this->hasher->check($plain, $user->getAuthPassword());
}

以上只是简单的分析了login的大体流程,感兴趣大家可以按照这个思路继续分析其他源码,有机会希望多交流,互相进步

laravel5.5用户认证源码分析的更多相关文章

  1. Django(64)频率认证源码分析与自定义频率认证

    前言 有时候我们发送手机验证码,会发现1分钟只能发送1次,这是做了频率限制,限制的时间次数,都由开发者自己决定 频率认证源码分析 def check_throttles(self, request): ...

  2. Django drf:序列化增删改查、局部与全局钩子源码流程、认证源码分析、执行流程

    一.序列化类的增.删.改.查 用drf的序列化组件   -定义一个类继承class BookSerializer(serializers.Serializer):   -写字段,如果不指定source ...

  3. Django-restframework 之认证源码分析

    Django-restframework 源码分析之认证 前言 最近学习了 django 的一个 restframework 框架,对于里面的执行流程产生了兴趣,经过昨天一晚上初步搞清楚了执行流程(部 ...

  4. drf认证源码分析

    补充: 一.django中间件之路由斜杠的自动添加源码 其实我们每次在写路由的时候,如果在路由层给他设置的是加/,但实际上我们在浏览器中输入的时候并没有加/发现也能调用,前面说了是浏览器内部走了重定向 ...

  5. Django-rest-framework源码分析----认证

    一.前言 1.1.安装 两种方式: github pip直接安装 pip install django-rest-framework 1.2.需要先了解的一些知识 理解下面两个知识点非常重要,djan ...

  6. Django rest framework源码分析(1)----认证

    目录 Django rest framework(1)----认证 Django rest framework(2)----权限 Django rest framework(3)----节流 Djan ...

  7. Django rest framework源码分析(一) 认证

    一.基础 最近正好有机会去写一些可视化的东西,就想着前后端分离,想使用django rest framework写一些,顺便复习一下django rest framework的知识,只是顺便哦,好吧. ...

  8. django身份认证、权限认证、频率校验使用及源码分析

    一. 身份认证源码分析 1.1 APIView源码的分析 APIView源码之前分析过https://www.cnblogs.com/maoruqiang/p/11135335.html,里面主要将r ...

  9. Django之REST framework源码分析

    前言: Django REST framework,是1个基于Django搭建 REST风格API的框架: 1.什么是API呢? API就是访问即可获取数据的url地址,下面是一个最简单的 Djang ...

随机推荐

  1. 百万级数据库SQL优化大总结

    网上关于SQL优化的教程很多,但是比较杂乱.近日有空整理了一下,写出来跟大家分享一下,其中有错误和不足的地方,还请大家纠正补充. 这篇文章我花费了大量的时间查找资料.修改.排版,希望大家阅读之后,感觉 ...

  2. 如何通过C#实现网页信息采集的方法总结

    Internet上有着极其庞大的资源信息,各行各业的信息无所不有.网页的信息搜集就是获取网页的数据,然后通过程序分析,将有用的数据提取分离出来.搜索引擎工作的一部分就是网页数据抽取.比如编制程序抽取新 ...

  3. powershell远程连接

    最近因为工作的需要看了看powershell相关的知识,个人总结了一点有关于powershell远程连接需要做的步骤,希望对别人有所帮助. 使用powershell远程连接,需要进行 设备的配置: 1 ...

  4. Windows Python 版本切换工具 --- Switch Python Version Tool For Windows

    2018年1月13日 更新: 如果要用到不同版本的Python 请使用 virtualenv, pip install virtualenv  , 我做的这个工具可以拿来维护下环境变量~~ 填好路径自 ...

  5. MySQL入门很简单: 4 创建 修改删除表

    1. 创建表的方法 1)创建表的语法形式 首先,选择数据库: USE 数据库名: 创建表: CREATE TABLE 表名 (属性名 数据类型 [完整性约束条件], 属性名 数据类型 [完整性约束条件 ...

  6. 修改hosts工具推荐SwitchHosts

    推荐一个修改hosts的工具.适合平时工作中经常修改hosts的开发测试. 下载地址:https://oldj.github.io/SwitchHosts/ 可以按各种环境或者项目添加,用的时候打开或 ...

  7. OpenCV2马拉松第5圈——线性滤波

    收入囊中 这里的非常多内容事实上在我的Computer Vision: Algorithms and ApplicationsのImage processing中都有讲过 相关和卷积工作原理 边界处理 ...

  8. 火车进出站(POJ1363)

    题目链接:http://poj.org/problem?id=1363 #include <stdio.h> #include <stack> using namespace ...

  9. Hubtown(最大流)

    Hubtown 时间限制: 1 Sec  内存限制: 128 MB提交: 23  解决: 11[提交] [状态] [讨论版] [命题人:admin] 题目描述 Hubtown is a large N ...

  10. glocktop

    glocktop: Display or print active GFS2 locks. Index of glocktop man page Read glocktop man page on L ...