Laravel 5.3 auth中间件底层实现详解(转)

1. 注册认证中间件, 在文件 app/Http/Kernel.php 内完成:

protected $routeMiddleware = [
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'checkuid' => \App\Http\Middleware\CheckUid::class,
];


2. 认证中间件的源码
文件:vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php 。其中:

use Illuminate\Contracts\Auth\Factory as Auth;
public function __construct(Auth $auth)
{
    $this->auth = $auth; //Auth 工厂类,这里注入的是 Illuminate\Auth\AuthManager
}

public function handle($request, Closure $next, ...$guards)
{
    $this->authenticate($guards);
    return $next($request);
}

protected function authenticate(array $guards)
{
    if (empty($guards)) {//如果没有指定guard 则使用默认
        return $this->auth->authenticate(); //通过Illuminate\Auth\AuthManager\__call() 调用 创建guard 实例,并调用guard 实例的 authenticate() 方法进行认证
    }
 
    foreach ($guards as $guard) {
        if ($this->auth->guard($guard)->check()) {//使用指定的guard中第一个能成功认证的
            return $this->auth->shouldUse($guard);//将指定guard设置为 本次请求的默认guard。(本次请求后续获取authed user时,都通过这里设置的guard进行)
        }
    }
 
    throw new AuthenticationException('Unauthenticated.', $guards);
}


2.1 $this->auth->authenticate(); //进行身份认证
文件: vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php

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


2.2 $this->guard() //获取guard实例
文件: vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php

public function guard($name = null)
{
    $name = $name ?: $this->getDefaultDriver();
     
    return isset($this->guards[$name])
    ? $this->guards[$name] //单例
    : $this->guards[$name] = $this->resolve($name); //获取 guard 实例
}

public function getDefaultDriver()
{
    return $this->app['config']['auth.defaults.guard']; //从配置文件内读取默认guard
}

protected function resolve($name)
{
    $config = $this->getConfig($name); //获取指定guard配置信息
     
    if (is_null($config)) {
        throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
    }
     
    if (isset($this->customCreators[$config['driver']])) {//如果设置了自定义工厂,则使用之
        return $this->callCustomCreator($name, $config);
    }
    
    //类似 createSessionDriver, createTokenDriver 等格式
    $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.");
}
 
public function createSessionDriver($name, $config)
{
    $provider = $this->createUserProvider($config['provider']);
     
    $guard = new SessionGuard($name, $provider, $this->app['session.store']);
     
    //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;
}

 

2.3 $this->guard()->authenticate() //使用获取的 guard 实例进行身份认证
文件: vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
类中 use 了 GuardHelpers trait
文件:vendor/laravel/framework/src/Illuminate/Auth/GuardHelpers.php

public function authenticate()
{
    if (! is_null($user = $this->user())) {
        return $user;
    }
 
    throw new AuthenticationException;
}

文件: vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php //此方法是真正进行身份认证的地方!!!!

public function user()
{
    if ($this->loggedOut) {
        return;
    }
     
    // If we've already retrieved the user for the current request we can just
    // return it back immediately. We do not want to fetch the user data on
    // every call to this method because that would be tremendously slow.
    if (! is_null($this->user)) {
        return $this->user;
    }
     
    $id = $this->session->get($this->getName()); //从session中获取用户ID。已登录用户的用户ID会被存储在Session内。
     
    // First we will try to load the user using the identifier in the session if
    // one exists. Otherwise we will check for a "remember me" cookie in this
    // request, and if one exists, attempt to retrieve the user using that.
    $user = null;
     
    if (! is_null($id)) {
        if ($user = $this->provider->retrieveById($id)) { //通过Illuminate\Auth\EloquentUserProvider 的retrieveById() 方法,获取用户信息,并返回User Model
            $this->fireAuthenticatedEvent($user);
        }
    }
     
    // If the user is null, but we decrypt a "recaller" cookie we can attempt to
    // pull the user data on that cookie which serves as a remember cookie on
    // the application. Once we have a user we can return it to the caller.
    $recaller = $this->getRecaller();//获取认证cookie(登录时选中记住我,服务端会向浏览器设置一个认证cookie,其中包括 remember_token,下次可以直接使用这个认证cookie进行登录)
     
    if (is_null($user) && ! is_null($recaller)) {
        $user = $this->getUserByRecaller($recaller); //使用 remember_token 从数据库中获取用户信息 (最终是委托 Illuminate\Auth\EloquentUserProvider::retrieveByToken() 方法来取数据)
         
        if ($user) {
            $this->updateSession($user->getAuthIdentifier()); //将用户ID保存到Session
            $this->fireLoginEvent($user, true);
        }
    }
     
    return $this->user = $user;
}


原文地址:http://www.cnblogs.com/tao100/p/6073542.html

posted @ 2017-09-06 15:21  chy1000  阅读(356)  评论(0编辑  收藏  举报