【问题标题】:Symfony on Kubernetes - New Session is started on each requestKubernetes 上的 Symfony - 在每个请求上启动新会话
【发布时间】:2020-11-05 23:23:03
【问题描述】:

使用 docker 在我的本地完美运行应用程序。

当我部署它时,我不明白为什么每次请求都会启动一个新会话。似乎不能来自代码,因为它完全一样。

会话存储在 redis 数据库中(如果我使用文件系统会话,我也会遇到同样的错误)。在那里我可以看到创建的所有新会话。 (见最后一个代码块)。

从日志中我可以清楚地识别出$request->getSession()->getId() 在每个请求上都发生了变化,但 PHPSESSID cookie 没有变化。

例如:

第一个请求

[2020-11-02 15:03:59] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\\Controller\\SecurityController::login"},"request_uri":"https://foo.bar.dev/login","method":"POST"} []
[2020-11-02 15:03:59] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticators":1} []
[2020-11-02 15:03:59] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
[2020-11-02 15:03:59] app.DEBUG: [LoginFormAuthenticator::supports] $request session id => 6491ddf4e8f3e2eaa22b44b3a98c094a [] []
[2020-11-02 15:03:59] app.DEBUG: [LoginFormAuthenticator::supports] $_COOKIE =>  {"PHPSESSID":"87cf6185b652f8d713c45031ebe6d8a4"} []

第二个

[2020-11-02 15:04:33] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\\Controller\\SecurityController::login"},"request_uri":"https://foo.bar.dev/login","method":"POST"} []
[2020-11-02 15:04:33] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticators":1} []
[2020-11-02 15:04:33] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"main","authenticator":"App\\Security\\LoginFormAuthenticator"} []
[2020-11-02 15:04:33] app.DEBUG: [LoginFormAuthenticator::supports] $request session id => 41b08dac8a803337a48dca7d5b33b840 [] []
[2020-11-02 15:04:33] app.DEBUG: [LoginFormAuthenticator::supports] $_COOKIE =>  {"PHPSESSID":"87cf6185b652f8d713c45031ebe6d8a4"} []

KUBERNETES

ingress-nginx.yaml

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: secured-front
  namespace: foo-apis-dev
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/affinity-mode: "persistent"
    nginx.ingress.kubernetes.io/session-cookie-name: "PHPSESSID"
    nginx.ingress.kubernetes.io/session-cookie-path: "/"
    nginx.ingress.kubernetes.io/session-cookie-samesite: "Lax"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800000"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800000"
spec:
  tls:
    - hosts:
        - bar.foo.dev
      secretName: tls-secret
  rules:
    - host: bar.foo.dev
      http:
        paths:
          - backend:
              serviceName: bar-nginx
              servicePort: 80
            path: /(.*)

Symfony APP

security.yaml

[...]
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            anonymous: lazy
            pattern: ^/.*
            logout:
                path: app_logout
                target: login

            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
[...]

services.yaml

[...]
    Redis:
        class: Redis
        calls:
            - connect:
                  - '%env(REDIS_HOST)%'
                  - '%env(int:REDIS_PORT)%'

    Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler:
        arguments:
            - '@Redis'
            - { prefix: 'admin_phpsess_' }
[...]

packages.framework.yaml

[...]
    session:
        handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler
        cookie_secure: auto
        cookie_samesite: lax
[...]

REDIS

127.0.0.1:6379> KEYS *admin*
1) "admin_phpsess_245e4a79fe35e2320943770061884c24"
2) "admin_phpsess_0ff29464322b3c2cfc5d8f5fd323ef75"
3) "admin_phpsess_26812c17f93a5d28a71853b77ac85386"
4) "admin_phpsess_7fbae6f0b1fdbe9576e41c9eee2cd60f"

版本:

  • PHP 7.4.12
  • Symfony 4.4
  • Kubernetes 1.17.9
  • redis (pecl) 5.3.2

重要提示

问题在于 redis 配置。

我采取了使用PdoSessionHandler 的步骤,它有效。问题来自 Redis 和/或 Kubernetes,我已经尝试了 2 个小时来指出产生此错误但目前不可能的配置。

【问题讨论】:

  • 在您的情况下,容器参数 framework.session.name 和 PHP INI 配置指令 session.name 的值是多少?如果 framework.session.name 未定义,Symfony 会退回到 php.ini 中的 session.name 指令。 /login 是否在您的防火墙配置中定义为“匿名”路由。 security.yml ?
  • 如果我转储一个 phpinfo 我得到 => session.name PHPSESSID
  • 查看我的更新答案。
  • 嗨@BastienSander - 你有没有想过这个?

标签: php symfony session kubernetes


【解决方案1】:

nginx.ingress.kubernetes.io/session-cookie-path: "/" 设置为而不是/(.*) 正则表达式。

Symfony 的framework.session.cookie_path 的默认参数也是/。 (documentation)

进一步将nginx.ingress.kubernetes.io/session-cookie-name更改为"INGRESSCOOKIE"或省略注释。

nginx 入口的会话 cookie 用于确定初始请求被路由到哪个 pod,并将任何进一步的请求路由到完全相同的 pod。

它是一个不同于 PHP 会话的会话 cookie,因此应该有一个不同的 cookie 名称。入口会话 cookie 已创建,并且可能会用您的配置覆盖 php 会话 cookie。

如果您使用的是 redis 会话,则不需要将连续请求路由到集群中的同一个 pod。

【讨论】:

  • 我改成了cookie-name。仍然有同样的问题。即使有两个标题:set-cookie: INGRESSCOOKIE=87cf6185b652f8d713c45031ebe6d8a4; Expires=Sun, 22-Nov-20 15:46:55 GMT; Max-Age=1728000; Path=/; Secure; HttpOnly; SameSite=Lax x-powered-by: PHP/7.4.12set-cookie: PHPSESSID=3931389ee24b9d42b9a06af0c0f1692f; path=/; HttpOnly; SameSite=lax
  • 您是否清除了 cookie 并验证 - 使用您当前的配置 - Set-Cookie 处理程序实际上确实通过了您的浏览器/客户端的入口?或者PHPSESSID 可能只是之前请求/配置的剩余部分?
  • 是的,我清除了它。会不会是过期了?在 Firefox 中显示为“会话”?
  • 好了87cf6185b652f8d713c45031ebe6d8a4 是入口cookie 会话。不是 PHP 的。它没有改变。将会话 ID 与 POST 请求到 /login 之后的后续不同路由进行比较。至少在某些时候PHPSESSID cookie 被 nginx 入口覆盖。这就解释了为什么 PHP/symfony 找不到该会话 id 并打开一个新的。再次进行身份验证也可能会给您一个新的会话 ID。因此,验证并访问防火墙后的路由作为测试正确会话 ID 的第二个请求。
  • 不幸的是,PHPSESSID 确实会“随机”更改,有时在同一会话的 10 秒后,响应中会出现标题 set-cookie PHPSESSID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; HttpOnly; SameSite=lax
猜你喜欢
  • 2018-08-10
  • 2020-07-13
  • 1970-01-01
  • 2021-05-30
  • 2016-05-21
  • 2021-08-19
  • 2015-07-25
  • 1970-01-01
  • 2017-06-17
相关资源
最近更新 更多