Symfony2 FOSUserBundle不使用UserManager提供缓存的用户实体

时间:2014-12-22 18:25:04

标签: php symfony doctrine-orm redis fosuserbundle

我目前正在尝试在Symfony2中构建一个(希望很快)的网站。我正在使用FOSUserBundle轻松管理用户。我编写了一个自定义CacheManager来存储Redis中的实体并获取由Doctrine管理的有效实体。我的自定义UserManager使用此服务更快地提供用户数据。这一切都很安静,但实际上UserManager似乎被忽略了。每个请求都会导致数据库查询。

我对FOSUserBundle的配置(sry。必须用'XXX'替换项目名称):

fos_user:
db_driver: orm
firewall_name: main
user_class: XXX\MainBundle\Entity\User
registration:
    form:
        type: XXX_user_registration
        validation_groups: [XXXRegistration]
    confirmation:
        enabled:    true
        template: XXXMainBundle:E-Mail:registration.email.html.twig
        from_email:
            address:        registrierung@XXX.XXX
            sender_name:    XXX Registrierung
profile:
    form:
        type: XXX_user_profile
        validation_groups: [XXXProfile]
resetting:
    email:
        template: XXXMainBundle:E-Mail:resetting.email.html.twig
            from_email:
                address:        reset@XXX.XXX
                sender_name:    XXX.XXX
service:
    mailer: fos_user.mailer.twig_swift
    user_manager: XXX_main_bundle.security.user_manager

我的服务配置:

    XXX_main_bundle.security.user_manager:
    class: XXX\Bundle\MainBundle\Security\UserManager
    arguments: [@XXX_main_bundle.cache_manager, @fos_user.entity_manager, @fos_user.util.canonicalizer.default, @security.password_encoder]

我的安全配置:

security:
providers:
    fos_userbundle:
        id: fos_user.user_provider.username_email

encoders:
    FOS\UserBundle\Model\UserInterface: sha512

role_hierarchy:
    ROLE_ADMIN:       ROLE_USER
    ROLE_SUPER_ADMIN: ROLE_ADMIN
    ROLE_DEVELOPER:   ROLE_SUPER_ADMIN

firewalls:
    main:
        pattern: .*
        form_login:
            provider:   fos_userbundle
            check_path: /login_check
            login_path: /login
        logout:
            path: /logout
        anonymous:    true
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    login:
        pattern: ^/login$
        security: false

access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin/, role: ROLE_ADMIN }

我无法向您显示我的UserManager和我的CacheManager,但如果调用并手动使用它们,它们工作正常!我还尝试编写一个依赖于UserManager的自定义UserProvider。但这总是导致错误:

  

CheckExceptionOnInvalidReferenceBehaviorPass.php第59行中的ServiceNotFoundException:   服务“security.authentication.manager”依赖于不存在的服务“security.user.provider.concrete.fos_userbundle”。

如果我同时启用两个UserProviders,则错误消失但UserManager仍然被忽略。 如果我使用的是FOSUserBundle的内置命令,但是当Symfony2从当前Session加载User时,它似乎就被使用了。

Sry基因。因为我的英语不好而且可能是愚蠢的问题,但我对任何批评都持开放态度。

THX, Justus Klein

编辑1:似乎我的UserManager没有被完全忽略。它从缓存中返回用户,但Symfony2仍然触发数据库查询以获取用户。

编辑2:发现来自FOSUserBundle的UserProvider的刷新功能从数据库而不是通过UserManager(wtf?)加载用户本身。所以重写UserProvider似乎就是一个线索。但如果我将其替换,我仍然会收到以下错误:

  

CheckExceptionOnInvalidReferenceBehaviorPass.php第59行中的ServiceNotFoundException:   服务“security.authentication.manager”依赖于不存在的服务“security.user.provider.concrete.fos_userbundle”。

编辑3:我能够通过赋予它与FOS Bundle中的密钥相同的密钥来覆盖UserProvider:

security:
providers:
    fos_userbundle:
        id: xxx_main_bundle.security.user_provider

这不是最佳实践^^没有一切正常。我认为这是最好的&存储用户的最快方式。

1 个答案:

答案 0 :(得分:3)

最好的解决方案是启用Doctrine ORM 2.5中提供的二级缓存功能,该功能完全执行:它在Redis(或您配置的任何其他缓存)中缓存实体,以便更快地检索它们。

当FOSUserBundle通过用户名加载用户时,这将无济于事(因为ORM在其SLC中使用id作为标识符,而不是用户名),但只有在提交登录表单或阅读记住我时才会发生这种情况如果您使用此功能,请使用Cookie。但是,它适用于refresh用户通过主键加载的位置(以及项目的每个其他位置都需要通过主键加载用户)。当用户更新时,Doctrine还将负责更新缓存,以便您获得有效数据(尽管不使用ORM也不要编辑用户)。

如果你想通过用户名优化用户加载,你可以编写自己的UserProvider,它可以在Redis中保持用户名和主键之间的映射,然后通过主键向Doctrine请求User对象(可以读取它)从ORM缓存然后),同时保持主要刷新,如在FOSUserBundle自己的提供程序中完成(这是出于安全原因)。然后,此服务可以直接使用UserManager或Doctrine通过用户名加载用户,以防用户名到ID缓存。
这里不再需要覆盖UserManager,因为它不再用于身份验证的关键路径。