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

Dan*_*ell 7 facebook ruby-on-rails devise omniauth omniauth-facebook

我在Rails 4应用程序中使用Devise 3.5和Omniauth.我创建了与Facebook的集成,允许用户将他们的Facebook帐户连接到我的应用程序.目前,当用户点击连接按钮时,它们会被发送到/user/auth/facebook然后重定向到Omniauth生成的回调网址:/user/auth/facebook/callback.我想要做的是在某些情况下手动覆盖此回调网址 - 这意味着我不想在初始化程序中覆盖它 - 使用完全限定的URL.例如,如果用户开始使用,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)
Run Code Online (Sandbox Code Playgroud)

我也试过换callback_pathredirect_urlredirect_uri,但似乎没什么用.当我看到系统产生的链接,它确实有回调作为URL参数,但是当我点击链接,我重定向回默认的回调URL,而不是自定义回调URL.

Dan*_*ell 2

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

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
Run Code Online (Sandbox Code Playgroud)

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

class AuthRedirect
    def self.matches?(request)
        request.subdomain.present? && request.subdomain == 'auth'
    end
end
Run Code Online (Sandbox Code Playgroud)

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

然后OmniauthCallbacksController#facebook我可以从omniauth参数中提取用户的id,如下所示:

auth = env["omniauth.auth"]
contact = Contact.find(env['omniauth.params']['contact_id'])
Run Code Online (Sandbox Code Playgroud)

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