如何在Symfony2中使用FOSFacebookBundle通过Facebook登录一个单独的url


How to make a separate url for signin via Facebook using FOSFacebookBundle in Symfony2

我需要有一个单独的url的纯登录形式(用户名/密码)已经存在于/login,和一些url/login-via-facebook通过FOSFacebookBundle oauth过程登录。

现在我无法理解如何通过url触发oauth-facebook过程,只有当我尝试访问在"access_control"中列出的url时才有效。

提前感谢!


@Matt,非常感谢你的解释!我试着跟随你的答案,但仍然有一个问题,我没有提到我已经使用FOSUserBundle,

my security.yml:

providers:
    chain_provider:
      providers: [fos_userbundle, fos_facebook]
    fos_userbundle:
        id: fos_user.user_manager
    fos_facebook:
        id: fos_facebook.auth 
firewalls:      
    public:
      pattern:   ^/
      fos_facebook:
        app_url: ""
        server_url: ""
        login_path: /login
        check_path: /login_check/facebook
        provider: fos_userbundle
      fos_userbundle:
        login_path: /login
        check_path: /login_check/form
        provider: fos_userbundle
      anonymous: true
      logout:    true`

因此,此时它抛出一个异常:InvalidConfigurationException: Unrecognized options "fos_userbundle" under "security.firewalls.public",如果我在公共防火墙中将fos_userbundle更改为form_login(但我应该这样做吗?),它抛出一个异常You must configure the check path to be handled by the firewall using form_login in your security firewall configuration.

您检查过安检了吗?yml:

factories:
    - "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"

这很重要,因为它将对服务中缺少的选项收费。

诀窍是在防火墙中有两个分开的条目,一个用于表单登录,一个用于facebook登录。但在我的情况下,我有一个登录url,用户可以使用他的凭据登录,也可以使用FOSFacebookBundle单击Facebook连接通过Facebook OAuth2 API进行身份验证。下面是我的security.yml配置文件的示例,以使此工作:

security:
  factories:
    - "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
  providers:
    chain_provider:
      providers: [acme.form_provider, acme.facebook_provider]
    acme.form_provider:
      id: acme.user_provider.form
    acme.facebook_provider:
      id: acme.user_provider.facebook
  firewalls:
    dev:
      pattern:  ^/(_(profiler|wdt)|css|images|js)/
      security: false
    public:
      pattern:   ^/
      fos_facebook:
        app_url: "your_app_url"
        server_url: "your_server_url"
        login_path: /login
        check_path: /login_check/facebook
        provider: acme.facebook_provider
      form_login:
        login_path: /login
        check_path: /login_check/form
        provider: acme.form_provider
      anonymous: true
      logout:    true
  role_hierarchy:
    ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

这里是我的routing.yml文件的示例,用于定义使此工作所需的安全路由:

    # This is defined to let the user log in. The controller for
    # route display the login form and a facebook connect button
_security_login:
    pattern:   /login
    defaults:  { _controller: AcmeAcmeBundle:Main:login }
# This is defined for the form login authentication, 
# no controller is associated with it
_security_check_form:
    pattern:   /login_check/form
# This is defined for facebook login authentication, 
# a controller is associated with it but does nothing
_security_check_facebook:
    pattern:   /login_check/facebook
            defaults:  { _controller: AcmeAcmeBundle:Main:loginCheckFacebook }
_security_logout:
    pattern:   /logout
    defaults:  { _controller: AcmeAcmeBundle:Main:logout }

在使用security.yml之前,安全机制将在用户使用facebook登录之前检查使用表单登录的用户。这是因为在chain_provider中定义提供程序的顺序。对于每个请求,FOSFacebookBundle检查是否存在facebook oauth2 cookie,如果存在,则尝试加载您的用户。如果无法找到cookie,则身份验证过程将尝试另一个提供商,如果它是在facebook提供商之后定义的。

在您的情况下,当用户试图去到一个受保护的url(在access_control), facebook登录页面显示,他的身份验证,然后他被重定向到您的网站,cookie被发现,用户通过FOSFacebookBundle成功认证。要手动触发身份验证过程,请在您的站点上放置一个facebook连接按钮,然后用javascript将用户重定向到您站点的另一个页面。这样,cookie将由连接按钮设置,FOSFacebookBundle将在下一个请求时对他进行身份验证。我所做的是,当facebook连接按钮成功时,将用户重定向到javascript中facebook的login_check路径。这样,安全机制将把他重定向到安全配置中声明的位置。

我希望这将帮助你实现你想要的。如果有不清楚的地方,可以毫不犹豫地进一步提问。

@Follow-up # 1

实际上,您不能将fos_userbundle放在防火墙配置中的节点public下,因为它不是一个有效的选项。字符串fos_userbundle用于引用FOSUserBundle UserProvider类。我从未使用过这个包,但是阅读文档,你应该使用form_login。您可以查看步骤#5和下面的FOSUserBundle文档。您提到的错误很奇怪,因为它告诉您login_path不是由防火墙处理的,但由于防火墙匹配以/ (^/)开头的任何内容,因此情况就是这样。不知道哪里出了问题,但你的方向是对的。使用form_login并尝试检查为什么它不能从那里工作。

问候,
马特

这里有一个简单的Bundle示例,它实现了FOSUserBundle和FOSFacebookBundle,如果你想看的话https://github.com/ollietb/OhFOSFacebookUserBundle