具有多个防火墙和多个共享防护验证器的Symfony 3.4防火墙配置

时间:2019-11-14 18:57:51

标签: symfony authentication jwt symfony-3.4 lexikjwtauthbundle

这是一个Symfony 3.4应用程序,具有网站前端和访问同一后端的移动应用程序。用户可以通过

登录
  1. 提交用户名和密码(表单登录)
  2. 使用Google帐户进行身份验证
  3. 使用Facebook帐户进行身份验证

以前,只有一种登录方式(用户名和密码)。身份验证和防火墙配置有效。添加社交网络身份验证需要更改防火墙配置,现在防护身份验证已部分中断。

到目前为止,我有信心的是,我们需要为Web用户(主要)和移动应用程序用户(API)使用单独的防火墙。对Web用户进行一次身份验证,然后将已登录的用户信息存储在会话cookie中,但对移动应用程序用户进行身份验证时会收到每个传入请求。当移动用户成功登录后,他们将获得jwt令牌作为响应,并将随每个后续请求一起发送。

似乎最大的问题是其余的防火墙配置。在当前配置中,“主”防火墙按预期工作。但是,针对移动用户的“ api”防火墙的某些问题已损坏。登录使用相同的防护验证器,以便它们按预期返回jwt令牌。但是,与令牌一起发送的后续请求都将导致403访问被拒绝响应。我怀疑词汇认证器永远不会从请求中获取jwt令牌,因此用户似乎从未登录过。

身份验证器已经过测试,对于网络用户和移动用户而言,它们似乎都可以正常工作。 lexik jwt身份验证器的配置也正确-或自移动用户仍然只有一个身份验证器以来就没有更改。这意味着键,密码短语,令牌ttl。

一个可行的想法是为移动登录URL和其余的移动路由设置单独的防火墙,因为它们由不同的身份验证器处理。我在没有任何改善的情况下进行了尝试:登录可以正常工作,但jwt身份验证没有。以下是security.yml的相关部分:

security:
...
  providers:
    db_users:
      entity: { ... }
  firewalls:
    dev:
      pattern: ^/(_(profiler|wdt)|css|images|js|api)/(password/reset)
      security: false
    api:
      pattern: ^/api/
      stateless: true
      lexik_jwt: ~
      anonymous: false
      guard:
        provider: db_users
        authenticators:
          - main.form_login_authenticator
          - main.google_login_authenticator
          - main.fb_login_authenticator
          - lexik_jwt_authentication.jwt_token_authenticator
        entry_point: main.form_login_authenticator
    main:
      pattern: ^/
      guard:
        provider: db_users
        authenticators:
          - main.form_login_authenticator
          - main.google_login_authenticator
          - main.fb_login_authenticator
        entry_point: main.form_login_authenticator
      form_login:
        remember_me: true
        login_path: login
        check_path: login
        always_use_default_target_path: true
        default_target_path: /redirect
        target_path_parameter: _target_path
        use_referer: false
        require_previous_session: false
      anonymous: true
...

这里发生了什么事?我应该如何调试此问题? (除了使用邮递员模拟来自移动应用程序的json请求)

其他信息:所有三个自定义身份验证器都创建一个jwt令牌,例如:

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
  {
    // mobile users:
    if ( $request->getRequestFormat() == 'json') {
      return new JsonResponse(['token' => $this->jwtManager->create($token->getUser())]);
  // web users handled here

  }

然后关于访问模式(或如何处理请求以及由哪个身份验证器进行处理),这是main.form_login_authenticator的示例

public function supports(Request $request)
{
    return ('login' === $request->attributes->get('_route') || 'api_login_check' === $request->attributes->get('_route'))
        && $request->isMethod('POST');
}

不过,身份验证器似乎可以正常工作。登录作品。无法使用jwt令牌保持登录状态。

2 个答案:

答案 0 :(得分:1)

终于可以了。该解决方案的主要思想是分离防火墙:一个用于移动登录路由,另一个用于其余的移动(api)路由。这是有效的配置,省略了三个点的标记。 main防火墙已按照问题所示进行配置。

security:
  ...
  firewalls:
    ...
    api_login:
      pattern: ^/api/(login|google-login|fb-login)
      stateless: true
      anonymous: true
      guard:
        provider: db_users
        authenticators:
          - main.form_login_authenticator
          - main.google_login_authenticator
          - main.fb_login_authenticator
        entry_point: main.form_login_authenticator
    api:
      pattern: ^/api
      stateless: true
      guard:
        provider: db_users
        authenticators:
          - lexik_jwt_authentication.jwt_token_authenticator
    main: 
      ...

身份验证器服务名称的前缀最初来自防火墙main的名称,这不再有意义,因为它们现在已在多个防火墙之间共享。

答案 1 :(得分:0)

首先,对于api防火墙,您应该仅具有jwt身份验证器,因为即使auth也是如此。完成社交网络后,您必须生成自己的jwt令牌。

第二,您可以将您的访问模式发送给我们吗?这可以为我们提供更多线索。

第三,我不确定api防火墙的入口点是否应与形式一(https://symfony.com/doc/current/components/security/firewall.html#entrypoint)相同