美文网首页我爱编程
Laravel框架 之 Session

Laravel框架 之 Session

作者: 诺之林 | 来源:发表于2018-04-17 15:19 被阅读30次

    本文的示例代码参考session

    目录

    总述

    • Session基于以下中间件
    StartSession # vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php
    
    EncryptCookies # vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php
    
    • Session的完整流程如下
    request -> EncryptCookies (decrypt) -> StartSession (loadSession) -> StartSession (add session to request)
    
    response <- EncryptCookies (encrypt) <- StartSession (add cookie to response) <- StartSession (saveSession)
    

    StartSession

    // app/Http/Kernel.php
    class Kernel extends HttpKernel
    {
        protected $middlewareGroups = [
            'web' => [
                // 设置session中间件
                \Illuminate\Session\Middleware\StartSession::class,
            ],
        ];
    }
    
    // vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php
    class StartSession
    {
        // 处理$request
        public function handle($request, Closure $next)
        {
            // 设置$request session
            if ($this->sessionConfigured()) {
                $request->setLaravelSession(
                    $session = $this->startSession($request)
                );
            }
    
            // $request next中间件
            $response = $next($request);
    
            // 添加cookie至response
            if ($this->sessionConfigured()) {
                $this->addCookieToResponse($response, $session);
            }
    
            return $response;
        }
    
        protected function startSession(Request $request)
        {
            return tap($this->getSession($request), function ($session) use ($request) {
                $session->setRequestOnHandler($request);
    
                $session->start();
            });
        }
    
        protected function addCookieToResponse(Response $response, Session $session)
        {
            // 保存持久化session
            if ($this->usingCookieSessions()) {
                $this->manager->driver()->save();
            }
    
            // 添加cookie至response
            if ($this->sessionIsPersistent($config = $this->manager->getSessionConfig())) {
                $response->headers->setCookie(new Cookie(
                    $session->getName(), $session->getId(), $this->getCookieExpirationDate(),
                    $config['path'], $config['domain'], $config['secure'] ?? false,
                    $config['http_only'] ?? true, false, $config['same_site'] ?? null
                ));
            }
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Session/Store.php
    class Store implements Session
    {
        public function start()
        {
            // 读取持久化session
            $this->loadSession();
    
            return $this->started = true;
        }
    
        protected function loadSession()
        {
            $this->attributes = array_merge($this->attributes, $this->readFromHandler());
        }
    
        protected function readFromHandler()
        {
            // 默认session持久化在file中 所以handler实例类型是: vendor/laravel/framework/src/Illuminate/Session/FileSessionHandler.php
            if ($data = $this->handler->read($this->getId())) {
                $data = @unserialize($this->prepareForUnserialize($data));
    
                if ($data !== false && ! is_null($data) && is_array($data)) {
                    return $data;
                }
            }
    
            return [];
        }
    }
    
    cat $(find storage/framework/sessions -name "[0-9a-zA-Z]*" | tail -n1)
    # a:3:{s:6:"_token";s:40:"preN7ziem0bBQ3T07b1YnoIvxCNmJJRcvtWl40wo";s:9:"_previous";a:1:{s:3:"url";s:21:"http://localhost:8000";}s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}}
    

    EncryptCookies

    // app/Http/Kernel.php
    class Kernel extends HttpKernel
    {
        protected $middlewareGroups = [
            'web' => [
                // 设置encrypt中间件
                \App\Http\Middleware\EncryptCookies::class,
                \Illuminate\Session\Middleware\StartSession::class,
            ],
        ];
    }
    
    // app/Http/Middleware/EncryptCookies.php
    class EncryptCookies extends Middleware
    {
        protected $except = [
            //
        ];
    }
    
    // vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php
    class EncryptCookies
    {
        public function handle($request, Closure $next)
        {
            // decrypt $request cookie -> 接着交给next中间件处理 -> 最后再encrypt $response cookie
            $response = $next($this->decrypt($request));
    
            return $this->encrypt($response);
        }
    
        protected function encrypt(Response $response)
        {
            foreach ($response->headers->getCookies() as $cookie) {
                if ($this->isDisabled($cookie->getName())) {
                    continue;
                }
    
                $response->headers->setCookie($this->duplicate(
                    // $this->encrypter实例类型是:vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php
                    $cookie, $this->encrypter->encrypt($cookie->getValue())
                ));
            }
    
            return $response;
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php
    class Encrypter implements EncrypterContract
    {
        // 使用对称加密算法加密session id 这里的key即是.env中的APP_KEY
        public function encrypt($value, $serialize = true)
        {
            $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
    
            $value = \openssl_encrypt(
                $serialize ? serialize($value) : $value,
                $this->cipher, $this->key, 0, $iv
            );
    
            $mac = $this->hash($iv = base64_encode($iv), $value);
    
            return base64_encode(json_encode(compact('iv', 'value', 'mac')));
        }
    }
    

    启动流程与IoC容器

    • 上述解释了Session的流程
    那么Session是如何和启动流程相关联的呢?
    
    框架又是如何通过IoC容器管理相关实例的呢?
    

    启动流程

    // public/index.php
    require __DIR__.'/../vendor/autoload.php';
    
    $app = require_once __DIR__.'/../bootstrap/app.php';
    
    $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
    );
    
    $response->send();
    
    $kernel->terminate($request, $response);
    
    // bootstrap/app.php
    $app = new Illuminate\Foundation\Application(
        realpath(__DIR__.'/../')
    );
    
    $app->singleton(
        Illuminate\Contracts\Http\Kernel::class,
        App\Http\Kernel::class
    );
    
    $app->singleton(
        Illuminate\Contracts\Debug\ExceptionHandler::class,
        App\Exceptions\Handler::class
    );
    
    return $app;
    
    // app/Http/Kernel.php
    class Kernel extends HttpKernel
    {
    }
    
    // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php
    class Kernel implements KernelContract
    {
        protected $bootstrappers = [
            \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
            \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
            \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
            \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
            \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
            \Illuminate\Foundation\Bootstrap\BootProviders::class,
        ];
    
        public function handle($request)
        {
            $response = $this->sendRequestThroughRouter($request);
    
            $this->app['events']->dispatch(
                new Events\RequestHandled($request, $response)
            );
    
            return $response;
        }
    
        protected function sendRequestThroughRouter($request)
        {
            $this->app->instance('request', $request);
    
            $this->bootstrap();
    
            return (new Pipeline($this->app))
                        ->send($request)
                        ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                        ->then($this->dispatchToRouter());
        }
    
        public function bootstrap()
        {
            if (! $this->app->hasBeenBootstrapped()) {
                $this->app->bootstrapWith($this->bootstrappers());
            }
        }
    }
    

    IoC容器

    // vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterProviders.php
    class RegisterProviders
    {
        public function bootstrap(Application $app)
        {
            $app->registerConfiguredProviders();
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Foundation/Application.php
    class Application extends Container implements ApplicationContract, HttpKernelInterface
    {
        public function registerConfiguredProviders()
        {
            $providers = Collection::make($this->config['app.providers'])
                            ->partition(function ($provider) {
                                return Str::startsWith($provider, 'Illuminate\\');
                            });
    
            $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
    
            (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
                        ->load($providers->collapse()->toArray());
        }
    }
    
    // config/app.php
    return [
        'providers' => [
    
            /*
             * Laravel Framework Service Providers...
             */
            Illuminate\Auth\AuthServiceProvider::class,
            Illuminate\Broadcasting\BroadcastServiceProvider::class,
            Illuminate\Bus\BusServiceProvider::class,
            Illuminate\Cache\CacheServiceProvider::class,
            Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
            Illuminate\Cookie\CookieServiceProvider::class,
            Illuminate\Database\DatabaseServiceProvider::class,
            Illuminate\Encryption\EncryptionServiceProvider::class,
            Illuminate\Filesystem\FilesystemServiceProvider::class,
            Illuminate\Foundation\Providers\FoundationServiceProvider::class,
            Illuminate\Hashing\HashServiceProvider::class,
            Illuminate\Mail\MailServiceProvider::class,
            Illuminate\Notifications\NotificationServiceProvider::class,
            Illuminate\Pagination\PaginationServiceProvider::class,
            Illuminate\Pipeline\PipelineServiceProvider::class,
            Illuminate\Queue\QueueServiceProvider::class,
            Illuminate\Redis\RedisServiceProvider::class,
            Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
            Illuminate\Session\SessionServiceProvider::class,
            Illuminate\Translation\TranslationServiceProvider::class,
            Illuminate\Validation\ValidationServiceProvider::class,
            Illuminate\View\ViewServiceProvider::class,
    
            /*
             * Package Service Providers...
             */
    
            /*
             * Application Service Providers...
             */
            App\Providers\AppServiceProvider::class,
            App\Providers\AuthServiceProvider::class,
            // App\Providers\BroadcastServiceProvider::class,
            App\Providers\EventServiceProvider::class,
            App\Providers\RouteServiceProvider::class,
    
        ],
    ];
    

    参考

    相关文章

      网友评论

        本文标题:Laravel框架 之 Session

        本文链接:https://www.haomeiwen.com/subject/qbqukftx.html