【问题标题】:Session Problem on Redis with Docker + Nginx + Yii2使用 Docker + Nginx + Yii2 在 Redis 上的会话问题
【发布时间】:2021-12-04 00:17:34
【问题描述】:

问题是,我在使用带有 Nginx + Yii2 + Redis 的 Docker 的会话时遇到问题。

我想在 Yii2 高级模板中的银行和前端使用相同的登录。

我刚刚配置好了,不使用Redis时它工作,但是当我使用Redis时,不工作。

我的配置是:

  • Yii2 高级版 2.0.43
  • Nginx 1.17.8
  • Redis 4-alpine

我的文件: docker-compose.yml

version: "3.2"
services:
   nginx:
       container_name: nginx
       image: nginx:1.17.8
       ports:
           - 805:80 #Yes, i use on port 805, its better for me ;-)
       volumes:
           - ./vhosts/nginx.conf:/etc/nginx/conf.d/site.conf
           - ./:/app
       links:
           - php
           - db
           - redis
   php:
       build: .
       container_name: php
       volumes:
           - ./:/app
       environment:
           - SESSION_HANDLER=redis
           - SESSION_PATH=tcp://redis:${REDIS_PORT}?auth=${REDIS_PASSWORD}
           - SESSION_MAX_TIME_LIFE=86400
   db:
       image: mysql:8
       ports:
           - '33065:3306' #Its my way, i use on port 33065, depending on each project
       volumes:
           - /var/lib/mysql
       environment:
           - MYSQL_ROOT_PASSWORD=654321
           - MYSQL_DATABASE=my-project-5

   redis:
       image: redis:4-alpine
       container_name: redis
       command: redis-server --requirepass ${REDIS_PASSWORD}
       ports:
           - ${REDIS_PORT}:${REDIS_PORT}

Dockerfile

FROM php:7.4-fpm-alpine
 

RUN apk add --no-cache --virtual .build-deps \
g++ make autoconf yaml-dev

RUN pecl install igbinary-3.1.2
RUN pecl install redis-5.1.1 \
pecl install xdebug-2.9.0

#se for usar o redis
COPY frontend/web/php.ini /usr/local/etc/php/php.ini

RUN docker-php-ext-install intl
RUN docker-php-ext-install pcntl
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install mbstring
RUN docker-php-ext-enable igbinary.so
RUN docker-php-ext-enable redis.so
RUN docker-php-ext-enable xdebug

RUN rm -rf /var/cache/apk/*
RUN apk del --purge .build-deps

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer

CMD ["php-fpm"]

/vhosts/nginx.conf

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on; ## listen for ipv6
    server_name proj5.local;

    set $base_root /app;
    root $base_root;

    error_log /var/log/nginx/advanced.local.error.log warn;
    access_log /var/log/nginx/advanced.local.access.log main;
    
    charset UTF-8;
    index index.php index.html;
    client_max_body_size 200m;
    fastcgi_read_timeout 2500;

    location / {
        root $base_root/frontend/web;
        try_files $uri $uri/ /frontend/web/index.php$is_args$args;

        location ~ ^/assets/.+\.php(/|$) {
            deny all;
        }
    }

    location /painel {
        alias $base_root/backend/web/;

        # prevent the directory redirect to the URL with a trailing slash
        location = /painel {
            # if your location is "/backend", try use "/backend/backend/web/index.php$is_args$args"
            # bug ticket: https://trac.nginx.org/nginx/ticket/97
            try_files $uri /backend/web/index.php$is_args$args;
        }

        try_files $uri $uri/ /backend/web/index.php$is_args$args;

        location ~ ^/painel/assets/.+\.php(/|$) {
            deny all;
        }
    }

    location ~ ^/.+\.php(/|$) {
        rewrite (?!^/((frontend|backend)/web|painel))^ /frontend/web$uri break;
        rewrite (?!^/backend/web)^/painel(/.+)$ /backend/web$1 break;

        fastcgi_pass php:9000; # proxy requests to a TCP socket
        #fastcgi_pass unix:/var/run/php-fpm.sock; # proxy requests to a UNIX domain socket (check your www.conf file)
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        include /etc/nginx/fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        try_files $fastcgi_script_name =404;
    }

    location ~ /\. {
        deny all;
    }
}

前端/web/php.ini

session.save_handler = ${SESSION_HANDLER}
session.save_path = ${SESSION_PATH}
session.gc_maxlifetime = ${SESSION_MAX_TIME_LIFE}

common/config/main.php

'components' => [
    'cache' => [
         'class' => 'yii\redis\Cache',
    ],
    'redis' => [
         'class' => 'yii\redis\Connection',
         'hostname' => 'redis',
         'port' => env("REDIS_PORT"),
         'password' => env("REDIS_PASSWORD"),
         'database' => 0,
     ],
    'session' => [
        'class' => 'yii\redis\Session',
    ],
...

PS:为了工作,我必须禁用它并禁用 Redis

前端/config/main.php

...
'components' => [
        'user' => [
            'identityClass' => 'common\models\Admin',
            'enableAutoLogin' => false,
            'identityCookie' => [
                'name' => 'backend-same-frontend',
                'httpOnly' => false,
            ],
        ],
        'session' => [
            'name' => 'advanced-backend-frontend',
            'savePath' => sys_get_temp_dir(),
        ],
        'request' => [
            'csrfParam' => '_csrf-frontend',
            'baseUrl' => '',
            'cookieValidationKey' => 'jhkbYUITFRuytkjHBkjhvguytRDuytcdIYUTdfiyOUgoligoiuytguioyFGOU',
        ],
...

backend/config/main.php

...
'components' => [
        'user' => [
            'identityClass' => 'common\models\Admin',
            'enableAutoLogin' => true,
            'identityCookie' => [
                'name' => 'backend-same-frontend',
                'httpOnly' => false,
            ],
        ],
        'session' => [
            // this is the name of the session cookie used for login on the backend
            'name' => 'advanced-backend-frontend',
            'savePath' => sys_get_temp_dir(),
        ],
        'request' => [
            'cookieValidationKey' => 'kjhIKUYTiyuRTIYUfkjhbVGFKJHGf87654HJGFKHGfkjyhgft',
            'csrfParam' => '_csrf-backend',
            'baseUrl' => '/painel',
        ],
...

项目在 URL 上运行:

当我说这就像一个魅力时,但只有当我不使用 Redis 时。

如果我使用 Redis,会话不会在后端和前端持续存在

Backend without Redis

Frontend without Redis

谁能帮帮我...

【问题讨论】:

    标签: php docker nginx redis yii2


    【解决方案1】:

    首先,我认为你在使用 Redis 时不需要frontend/web/php.ini,因为你将处理来自 Yii 的所有内容,而不是来自 php 配置,所以我只是说它没用。

    其次,由于您在两个应用程序之间共享大量组件,您可能希望将通用配置放入一些通用 php 文件中,并将它们包含在两个应用程序中。示例:

    将此添加到前端和后端配置中:

    <?php
    
    'session' => require(__DIR__ . '/../../common/config/session.php'),
    
    

    并创建common/config/session.php,内容为:

    <?php
    
    return [
        'class' => 'yii\redis\Session',
        'name' => 'my-app-name',
        // ...
    ];
    

    所以这样你只定义了一次组件,并且在两个地方都加载了完全相同的配置。

    然后一一检查usersessionrequest组件配置,并在IDE或文档中打开框架文件,检查是否有任何缺失的参数可能需要调整。

    此外,从这篇文章中,还有一个技巧可以检查 Redis 并查看是否以及哪些数据会生成到数据库中:

    https://www.cloudways.com/blog/yii2-redis-configuration/

    它可能会帮助您调试问题。

    更进一步,阅读本课程的 cmets:

    https://github.com/yiisoft/yii2-redis/blob/master/src/Session.php

    <?php
    
    // ...
    
        /**
         * @var string a string prefixed to every cache key so that it is unique. If not set,
         * it will use a prefix generated from [[Application::id]]. You may set this property to be an empty string
         * if you don't want to use key prefix. It is recommended that you explicitly set this property to some
         * static value if the cached data needs to be shared among multiple applications.
         */
        public $keyPrefix;
    
    
    

    您可以看到 Redis Session 类的 keyPrefix 配置,如果留空,则默认为您的应用程序的 ID。据我所知,使用高级模板,每个应用都有自己的 ID:

    <?php
    
    return [
        'id' => 'app-frontend',
    // ...
    

    所以这个小东西可以让 Redis 为每个应用程序使用单独的前缀保存会话。为了统一,必须设置keyPrefix

    我还建议从头开始并设置一个新的高级应用程序并实施所有内容,直到你让它工作。之后,返回您的应用并检查差异。

    【讨论】:

    • 亲爱的@Alexandru 非常感谢!我只是把:'keyPrefix' =&gt; 'session-same-backend-frontend', 放在会话配置上,就像一个魅力!非常感谢!! ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多