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. jstl Maven 依赖导致的 Jar 包冲突

    概述 Jar 包冲突是日常开发过程中,时常会遇到的问题.本文介绍由 jstl 的 Maven 依赖导致的 Jar 包冲突问题,以及对应的解决方法. jstl 的 Maven 依赖配置 <depe ...

  2. day003-List类、Set类

    (一) 知识回顾1. day002总结 泛型没有多态.如果泛型能实现多态,那么数据类型就不安全了.违背了设计泛型的初衷. 1.1 伪泛型 泛型只存在编译器,编译生成的字节码中,不存在泛型变量的. 1. ...

  3. April 3 2017 Week 14 Monday

    Don't worry about finding your soul mate. Find yourself. 欲寻佳侣,先觅本心. You may fail to find your soul m ...

  4. CSS:响应式下的折叠菜单(条纹式)

    原文:CSS: Responsive Navigation Menu 译文:CSS:响应式导航菜单 译者:dwqs 写在之前,关于如何制作响应式的下拉菜单:响应式下的下拉菜单 之前,我写了一篇关于怎么 ...

  5. 如何在win10中安装ArcGIS10.2

    在win10中安装ArcGIS10.2,完美兼容,下面将自己在win10界面下的安装方法给大家分享一下. 工具/原料   win10环境 ArcGIS10.2安装包, 安装包地址链接: 链接: htt ...

  6. 转:SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)

    转:https://www.cnblogs.com/zyw-205520/p/4771253.html 1.基本概念   1.1.Spring Spring是一个开源框架,Spring是于2003 年 ...

  7. Jmeter文件目录,功能简介

    1.Jmeter文件目录:1)bin文件: Jmeter启动:bin/jmeter.bat Jmeter日志文件:jmeter.log Linux的启动文件:Jmeter.sh Jmeter系统配置文 ...

  8. 2017.9.25 JSP内置对象的概述

    1.JSP的定义: 在JSP中是为了便于数据信息的存储.传递.获取,专门设置了九个内置对象, jsp内置对象是指他们是预先设定的,不需创建,每个对象都有自己的属性和方法. 2.JSP内置对象 对象名称 ...

  9. Java 字符串转码工具类

    StringConvertUtils.java package javax.utils; /** * 字符串转码工具类 * * @author Logan * @createDate 2019-04- ...

  10. 错误:javax.servlet.http.HttpServlet" was not found on the Java Build Path

    我们在用Eclipse进行Java web开发时,可能会出现这样的错误: The superclass javax.servlet.http.HttpServlet was not found on ...