如何在 symfony 中使用多个用户提供者 5. 如何链接它?

Posted

技术标签:

【中文标题】如何在 symfony 中使用多个用户提供者 5. 如何链接它?【英文标题】:How to Use multiple User Providers in symfony 5. How to chain it? 【发布时间】:2021-10-20 23:02:04 【问题描述】:

更新的代码和问题:

我使用 symfony Symfony 5.3.6。

我有两种用户:公司和候选人。 我想让他们能够在他们身边进行身份验证。 2个表格来自前端。 (但目前没有表格)。

我使用 lexik_jwt_authentication.jwt_token_authenticator 来验证我的两种用户。 这是我第一次尝试在我的 security.yaml 中为 2 个提供程序编写代码。 当我只有一个时,它起作用了。当我添加公司时,它不再。

这是我在 security.yaml 中更新的代码:

security:
# https://symfony.com/doc/current/security/experimental_authenticators.html
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#c-hashing-passwords
password_hashers:
    Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
    App\Entity\Candidate:
        algorithm: auto
    App\Entity\Company:
        algorithm: auto


# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
    app_candidate_provider:
        entity:
            class: App\Entity\Candidate
            property: email

    app_compagny_provider:
        entity:
            class: App\Entity\Company
            property: email
    app_users:
        chain:
            providers: ['app_candidate_provider', 'app_compagny_provider']

firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    
    login:
        pattern: ^/api/login
        stateless: true
        anonymous: false
        json_login:
            check_path: /api/login
            username_path: email
            password_path: password
            success_handler: lexik_jwt_authentication.handler.authentication_success
            failure_handler: lexik_jwt_authentication.handler.authentication_failure

    api:
        pattern: ^/api/
        stateless: true
        anonymous: false
        provider: app_users
        guard:
            authenticators:
                - lexik_jwt_authentication.jwt_token_authenticator

    main:
        # anonymous: lazy
        lazy: true
        provider: app_user_provider

        # activate different ways to authenticate
        # https://symfony.com/doc/current/security.html#firewalls-authentication

        # https://symfony.com/doc/current/security/impersonating_user.html
        # switch_user: true

# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
    # -  path: ^/admin, roles: ROLE_ADMIN 
    # -  path: ^/profile, roles: ROLE_USER 

    -  path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY 
    -  path: ^/api/candidates, roles: IS_AUTHENTICATED_FULLY 
    -  path: ^/api/company, roles: IS_AUTHENTICATED_FULLY 

现在,我的消息错误是:“没有为“login”防火墙上的“json_login”侦听器明确配置提供程序是不明确的,因为有多个注册提供程序..

我关注了这个帖子: Not configuring explicitly the provider for the "guard" listener on "x" firewall is ambiguous as there is more than one registered provider

通过替换

api:
            pattern: ^/api/
            stateless: true
            anonymous: false
            provider: app_users
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator

api:
            pattern: ^/api/
            stateless: true
            anonymous: false
            provider: 'app_candidate_provider'
            guard:
                authenticators:
                    - lexik_jwt_authentication.jwt_token_authenticator

还是不行

你知道我哪里出错了吗?

编辑:@mcsky 给出的最终答案是好的:

security:
  # https://symfony.com/doc/current/security/experimental_authenticators.html
  enable_authenticator_manager: true
  # https://symfony.com/doc/current/security.html#c-hashing-passwords
  password_hashers:
      Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
      App\Entity\Candidate:
          algorithm: auto
      App\Entity\Company:
          algorithm: auto


  # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
  providers:
      app_candidate_provider:
          entity:
              class: App\Entity\Candidate
              property: email

      app_compagny_provider:
          entity:
              class: App\Entity\Company
              property: email
      app_users:
          chain:
              providers: ['app_candidate_provider', 'app_compagny_provider']

  firewalls:
      dev:
          pattern: ^/(_(profiler|wdt)|css|images|js)/
          security: false
      
      login:
          pattern: ^/api/login
          stateless: true
          provider: app_users
          anonymous: false
          json_login:
              check_path: /api/login
              username_path: email
              password_path: password
              success_handler: lexik_jwt_authentication.handler.authentication_success
              failure_handler: lexik_jwt_authentication.handler.authentication_failure

      api:
          pattern: ^/api/
          stateless: true
          anonymous: false
          provider: app_users
          guard:
              authenticators:
                  - lexik_jwt_authentication.jwt_token_authenticator

      main:
          # anonymous: lazy
          lazy: true
          provider: app_candidate_provider

          # activate different ways to authenticate
          # https://symfony.com/doc/current/security.html#firewalls-authentication

          # https://symfony.com/doc/current/security/impersonating_user.html
          # switch_user: true

  # Easy way to control access for large sections of your site
  # Note: Only the *first* access control that matches will be used
  access_control:
      # -  path: ^/admin, roles: ROLE_ADMIN 
      # -  path: ^/profile, roles: ROLE_USER 

      -  path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY 
      -  path: ^/api/candidates, roles: IS_AUTHENTICATED_FULLY 
      -  path: ^/api/company, roles: IS_AUTHENTICATED_FULLY 

【问题讨论】:

实现什么?有什么不工作吗?您是否面临yaml 本身的任何问题? 请通过编辑为您的问题添加所有说明。如果您遇到任何错误,请添加消息 您在app_user_provider 之后缺少entity 行,我不确定您是否可以在一个提供程序中指定两个类。但是有chain provider,将两个具体的提供者(candidatecompany)添加到它,并将其用作防火墙中的提供者。文档有一个很好的例子(我已经链接了当前的,因为password_hashers 暗示你在 5.3 上)。 在链提供者声明中的两个提供者之前有一个providers 键,检查我更新的答案:) 错误信息很清楚,你必须为login防火墙声明一个用户提供者,因为你已经定义了很多(之前你只有一个,所以Sf接受它)。我为登录防火墙添加了provider: app_users,检查答案:) 【参考方案1】:

您不能将具有多个类的一个用户提供程序定义为一种配置。它不是为这样工作而设计的。 Symfony 在木头下执行 Symfony\Bridge\Doctrine\Security\User\EntityUserProvider 这个类,你可以看到它只适用于 propertyemail 字符串。

所以我建议你定义两个不同的用户提供者,每个类类型一个。

那么你可以试试这个配置吗?

providers:
    app_candidate_provider:
        entity:
            class: App\Entity\Candidate
            property: email
    
    app_compagny_provider:
        entity:
            class: App\Entity\Company
            property: email
    app_users:
        chain:
            providers: ['app_candidate_provider', 'app_compagny_provider']
firewalls:
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    
    login:
        pattern: ^/api/login
        stateless: true
        provider: app_users
        anonymous: false
        json_login:
            check_path: /api/login
            username_path: email
            password_path: password
            success_handler: lexik_jwt_authentication.handler.authentication_success
            failure_handler: lexik_jwt_authentication.handler.authentication_failure

    api:
        pattern: ^/api/
        stateless: true
        anonymous: false
        provider: app_users
        guard:
            authenticators:
                - lexik_jwt_authentication.jwt_token_authenticator

如果有什么不清楚或不起作用,请告诉我

【讨论】:

您忘记了api 节点吗? Symfony 使用您的firewalls.api 防火墙来验证在您的 API 上发出的每个请求。我从您的帖子中获取了配置,因此您可以使用它。 哦,我忘记了 yaml 路径中的一级,entity 丢失了^^'答案已更新 我更新了我的答案,以使用 msg 在您的问题中建议的链提供商的技巧。它现在应该可以完成工作了 这似乎是 yaml 中的一个错字 :) 你能用你的配置更新你的问题吗?

以上是关于如何在 symfony 中使用多个用户提供者 5. 如何链接它?的主要内容,如果未能解决你的问题,请参考以下文章

如何在多个页面中拆分长的 symfony 表单?

Symfony多个Ldap提供程序

如何在事件订阅者中访问Symfony 3.3中的登录用户,而不会丢失Web分析器

使用新的 Symfony 5 Authenticator 注册后如何手动验证用户?

Symfony 5:如何在登录前检查用户是不是被禁止

Symfony 4.4 Auth0 如何从应用程序中完全注销用户