Devise/OmniAuth 覆盖默认回调 url

Devise/OmniAuth Override default callback url

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

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

根据我的阅读,url 助手 omniauth_authorize_path 接受额外的参数作为参数传递。我试过像这样传递自定义回调路径,但没有成功:

user_omniauth_authorize_path(:facebook, callback_path: @custom_callback)

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

你试过 redirect_uri 了吗?

user_omniauth_authorize_path(:facebook, redirect_uri: @custom_callback)

编辑:抱歉,我错过了您的 post 的第二部分。

我实际上在生产中遇到了同样的问题,但它在临时环境中运行得很好。唯一的区别是分期的回调 url 多了一个子域 *.staging.domain.com

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

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

我昨天在讨论这个问题。 要么我提供一个静态回调 url 但 facebook 给我一个 CRSF 错误:

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

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

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

在这种情况下,我在 FG 登录过程中得到一个直接的非 matching/whitelisted 回调 url。

编辑 2:

很好!我做到了。我可以使用通配符子域进行 oauth 登录。

  1. 在您的设计初始值设定项中提供静态 callback_url
  2. 将域添加到您的会话存储中: 域:“.domain.com”

这样一来,我既没有收到 CRSF 错误,也没有收到不匹配的 CB url/whitelisted。

希望它对你有用!

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

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,然后将他们重定向回 https://auth.example.com/.

然后在 OmniauthCallbacksController#facebook 中,我可以像这样从 omniauth 参数中提取用户 ID:

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

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