Devise / OmniAuth覆盖默认的回调网址

时间:2016-03-10 15:33:54

标签: ruby-on-rails facebook devise omniauth omniauth-facebook

我在Rails 4应用程序中使用Devise 3.5和Omniauth。我创建了与Facebook的集成,允许用户将他们的Facebook帐户连接到我的应用程序。目前,当用户点击连接按钮时,它们会被发送到/user/auth/facebook,然后重定向到Omniauth生成的回调网址:/user/auth/facebook/callback。我想要做的是在某些情况下手动覆盖此回调网址 - 这意味着我不想在初始化程序中覆盖它 - 使用完全限定的网址。例如,如果用户在http://www.example.com/开始,我可能希望使用http://app.example.com/user/auth/facebook/callback覆盖默认回调网址。

我的应用具有动态子域,用户(几乎)总是会在子域上开始身份验证过程。不幸的是,Facebook似乎不支持oauth重定向网址中的通配符,这就是为什么我希望能够检测用户是否在子域中并将回调网址调整为我已在我的Facebook应用上列入白名单的内容以便授权过程成功。

根据我的阅读,url helper omniauth_authorize_path接受其他参数作为参数传递。我已经尝试过这样的自定义回调路径,但没有成功:

user_omniauth_authorize_path(:facebook, callback_path: @custom_callback)

我也尝试将callback_path更改为redirect_urlredirect_uri,但似乎没有任何效果。当我查看生成的链接时,它确实包含回调作为url中的参数,但是当我单击该链接时,我将重定向回默认回调网址而不是自定义回调网址。

2 个答案:

答案 0 :(得分:1)

你试过redirect_uri吗?

user_omniauth_authorize_path(:facebook, redirect_uri: @custom_callback)
编辑:对不起,我错过了你帖子的第二部分。

我实际上在生产中遇到了同样的问题,但它在暂存环境中运行良好。唯一的区别是关于暂存的回调网址还有一个子域名* .staging.domain.com

顺便提一下,您可以在设计初始化文件中提供静态callback_url:

config.oaumniauth :facebook, ..., callback_url: 'url right here'

我昨天就这个问题发表了这个问题。 我要么提供一个静态回调网址,但facebook会引发一个CRSF错误:

omniauth: (facebook) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected

或者我让devise动态设置callback_url,看起来像

https://*.domain.com/DEVISE_MODELS/auth/facebook

在这种情况下,我会在FG登录过程中获得一个直接的非匹配/白名单回调网址。

EDIT2:

GOOD!我做到了。我能够通过通配符子域登录oauth。

  1. 在您的设计初始化程序中提供静态callback_url
  2. 将域添加到会话存储中: 域名:" .domain.com"
  3. 由此我既没有得到CRSF错误也没有获得CB url /白名单。

    希望它能为你效力!

答案 1 :(得分:0)

这是我如何解决这个问题的方法。我确定还有其他方法,但这似乎是我能想到的最简单,最优雅的解决方案。

config/routes.rb我设置了auth子域名。我的所有Oauth连接请求将从不同的子域开始,然后设置Facebook以将这些用户转发回auth.example.com子域。

constraints AuthRedirect do
    devise_scope :contact do
        get '/auth/facebook/callback' => 'omniauth_callbacks#facebook'
        post '/auth/facebook/callback' => 'omniauth_callbacks#facebook'
    end
end

这是/lib/auth_redirect.rb。这只是检查子域是否为auth并捕获该流量。它位于我的路线列表的顶部,以便优先于其他子域。

class AuthRedirect
    def self.matches?(request)
        request.subdomain.present? && request.subdomain == 'auth'
    end
end

然后在我的客户端,当用户点击Connect with Facebook按钮时,我将其发送到/auth/facebook?contact_id=<id>。从这里开始,Devise将他们引导到Facebook,然后Facebook将其重定向回https://auth.example.com/

然后在OmniauthCallbacksController#facebook我可以从omniauth params中提取用户ID:

auth = env["omniauth.auth"]
contact = Contact.find(env['omniauth.params']['contact_id'])

从这里,我可以将凭据保存到数据库,并将用户重定向回相应的子域。此解决方案避免了CSRF令牌的问题,更重要的是,我不需要使用Ruby / ERB来构建用户在单击连接按钮时发送到的omniauth授权路径。