zoukankan      html  css  js  c++  java
  • Laravel 5.3 auth中间件底层实现详解(转)

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

    protected $routeMiddleware = [
        'auth' => IlluminateAuthMiddlewareAuthenticate::class,
        'auth.basic' => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class,
        'bindings' => IlluminateRoutingMiddlewareSubstituteBindings::class,
        'can' => IlluminateAuthMiddlewareAuthorize::class,
        'guest' => AppHttpMiddlewareRedirectIfAuthenticated::class,
        'throttle' => IlluminateRoutingMiddlewareThrottleRequests::class,
        'checkuid' => AppHttpMiddlewareCheckUid::class,
    ];


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

    use IlluminateContractsAuthFactory as Auth;
    public function __construct(Auth $auth)
    {
        $this->auth = $auth; //Auth 工厂类,这里注入的是 IlluminateAuthAuthManager
    }
    
    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(); //通过IlluminateAuthAuthManager\__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)) { //通过IlluminateAuthEloquentUserProvider 的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 从数据库中获取用户信息 (最终是委托 IlluminateAuthEloquentUserProvider::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

  • 相关阅读:
    MS SQL日期處理
    VS2005快捷键大全
    聯接遠程務器進行操作
    Zune XNA 开发(一,Hello Zune)
    Silverlight for Google Picasa
    Moonlight已经可以下载,目前是0.6版
    Silverlight 2 Beta 2发布
    在Silverlight 2 beta1中使用IronPython等动态语言
    如何在现有通过AttachDbFilename连接的Sql Express数据库上设置membership
    XNA Game Studio 3.0 CTP让Zune不仅仅是媒体播放器
  • 原文地址:https://www.cnblogs.com/chy1000/p/7484962.html
Copyright © 2011-2022 走看看