MIs在 symfony 5+ 中使用 prod 环境中的自定义查询时的功能

MIsfunction in symfony 5+ when using custom query in prod environment

提问人:Oscar Manuel Gómez Senovilla 提问时间:9/4/2023 最后编辑:Oscar Manuel Gómez Senovilla 更新时间:9/7/2023 访问量:49

问:

我正在开发一个使用 user@domain 进行登录的应用程序,一个实体用于域,另一个实体用于链接到域的用户。这个应用程序是开源的,因此您可以从 https://github.com/omgslinux/vmail/ 自由克隆。所有测试都在 debian 下进行。

我从symfony 3.x开始,这些功能在开发和部署到生产环境时仍然有效。然后,在升级到 5.x 和 6.x 时,将更改使用自定义查询进行登录的升级方式。我为新的登录系统进行了必要的更改,并且在开发中一切正常,但是我发现在部署到 prod 时,有一个 100% 可重现的奇怪行为,但我无法知道为什么会发生这种情况。

问题是,如果我使用域中 id == 0 的任何用户登录,一切正常,但如果域 id 为 != 0,我会被重定向到登录屏幕,就像登录错误一样,但没有错误消息。如果那时我手动输入我应该被重定向的 url,我会被重定向回登录。我已经在主页中转储了 $this->getUser(),并使用相同的凭据,而在 dev 中返回一个用户实体,在 prod 中返回 null。如果我在存储库中转储查询,则在转到主页之前,查询将返回预期的记录。

如果我强制输入错误的密码,我可以在屏幕上看到登录错误。

我已经用 apache 和 nginx 测试了这一点,将APP_ENV变量设置为“prod”。如果我将APP_ENV设置为“dev”,则一切正常,包括底部的调试栏。

我只在另外两台服务器中复制了生产部分,并得到了完全相同的结果。

重现结果:默认的 git 分支是 symfony 3.x,所以你必须克隆 symfony62 分支才能进行最新的更改。安装后,创建一个新域,然后创建该新域中的用户,并尝试使用此新用户登录。

下面是 security.yaml:

security:
    password_hashers:
      App\Entity\User:
        id: App\Utils\PassEncoder
    providers:
        app_vmail_users:
            entity:
              class: App\Entity\User
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            provider: app_vmail_users
            #logout_on_user_change: true
            form_login:
              login_path: login
              check_path: login
              username_parameter: _username
              password_parameter: _password
            logout:
              path: logout
              target: /

    access_control:
        - { path: ^/login, roles: ['PUBLIC_ACCESS'] }
        - { path: ^/admin, roles: ['ROLE_ADMIN'] }
        - { path: ^/manage, roles: ['ROLE_MANAGER'] }
        - { path: ^/user, roles: ['ROLE_USER'] }
    role_hierarchy:
        ROLE_ADMIN: [ROLE_MANAGER, ROLE_USER]
        ROLE_MANAGER: [ROLE_USER]

以及用户存储库类中的 loader 函数:

    public function loadUserByIdentifier(string $username): ?UserInterface
    {
        $a=explode('@', $username);
        if (count($a) != 2) {
            return null;
        }
        $user=$a[0];
        $domain=$a[1];
        return $this->createQueryBuilder('u')
            ->leftJoin('u.domain', 'd')
            ->where('u.name = :user AND d.name = :domain')
            ->setParameter('user', $user)
            ->setParameter('domain', $domain)
            ->getQuery()
            ->getOneOrNullResult();
    }

任何帮助都是值得赞赏的。提前致谢。

php apache 身份验证 symfony nginx

评论

0赞 Ian Kemp 9/4/2023
GitHub 存储库在这里是不可接受的;代码必须包含在问题本身中。
0赞 Oscar Manuel Gómez Senovilla 9/4/2023
您希望我在问题中包含代码的哪一部分?请告诉我。
1赞 Såpe 9/4/2023
通过单独阅读您的线程(不看您 4 年前的代码,为什么不分享更新的代码?),您正在尝试合并两个实体。这永远不适用于标准安全设置和您提供的用户存储库链接。主要原因是:您的数据库中没有以“username@domain”作为 ID 的用户。您应该考虑的是将自定义用户提供程序客户身份验证器结合使用。至少共享这两个文件的代码和你的 security.yaml 配置。
0赞 Oscar Manuel Gómez Senovilla 9/4/2023
我希望我添加的内容对你来说已经足够了。如果您需要其他东西,请告诉我。
0赞 Tim Lewis 9/7/2023
不要在标题中添加“已解决”。如果您找到了解决方案,请将其发布在下面的答案部分,而不是问题正文中。谢谢。

答:

0赞 Oscar Manuel Gómez Senovilla 9/7/2023 #1

我找到了一种让它工作的方法。通过保留 monolog 默认值,我在 prod () 中根本没有调试:config/monolog.yaml

when@prod:
    monolog:
        handlers:
            main:
                type: fingers_crossed
                action_level: error
                handler: nested
                excluded_http_codes: [404, 405]
                buffer_size: 50 # How many messages should be saved? Prevent memory leaks
            nested:
                type: stream
                path: php://stderr
                level: debug
                formatter: monolog.formatter.json
            console:
                type: console
                process_psr_3_messages: false
                channels: ["!event", "!doctrine"]
            deprecation:
                type: stream
                channels: [deprecation]
                path: php://stderr

由于在 dev 中我可以调试应用程序,因此我将“main”部分替换为相应的“dev”部分:

                type: stream
                path: "%kernel.logs_dir%/%kernel.environment%.log"
                level: debug
                channels: ["!event"]

在不删除缓存的情况下,我发现我开始在路径指示的 prod 中拥有日志,并且由于应用程序没有更改并且它正在“工作”,因此我没有做任何其他事情。然后,我想到了删除 prod 缓存,允许自动重新生成。做完这个之后...一切正常!!

我通过恢复 monolog 更改并完全删除 prod 缓存来重现这一点。结果是“旧”故障又回来了,所以我撤消了最新的更改,删除了缓存,然后从一开始就恢复了应有的工作。

所以,我想知道:当使用自定义查询登录时,prod 的默认 monolog 默认值是否始终有效?这可能是一个错误吗?我把这个问题留给开发人员或其他任何人来检查一下。