如何在设计中使用 http 身份验证并使用可选的omniauth 令牌作为身份验证令牌

发布于 2024-12-01 17:07:34 字数 581 浏览 1 评论 0原文

我们有一个使用 devise & 的 Rails 应用程序设置。 omn​​iauth 允许通过 facebook 身份验证登录。我们还有一个移动应用程序,当前正在使用 http 身份验证通过传递用户名和密码来登录 Rails 应用程序。密码或通过传入 http 身份验证令牌。到目前为止,这一切都效果很好。

该移动应用程序还能够通过 facebook 本身进行身份验证,并直接在其自身和 facebook 之间接收用户 facebook 令牌。

我想弥补这一差距,以便如果用户通过 facebook 从移动应用程序登录并拥有 facebook 令牌,则允许该 facebook 令牌用作 Rails 应用程序上的身份验证,就像他们通过 facebook 从 facebook 收到它一样浏览器。

最终结果是移动应用程序可以通过以下方式登录用户:

1) 用户名​​/密码 或者 2)http认证令牌 或者 3)omniauth(facebook)令牌

此外,在3)的情况下,如果用户尚不存在于rails应用程序上,则需要创建用户 - 现在已经使用浏览器端身份验证执行此操作,因此可能没有更多内容去做。

我怎样才能在设计结构中最好地实现这一点?

We have a rails app setup that uses devise & omniauth to allow logging in via facebook authentication. We also have a mobile app that is currently using http authentication to login to the rails app either by passing username & password or by passing in the http authentication token. This all works great so far.

The mobile app also has the ability to authenticate with facebook itself and receive the user facebook token directly between itself and facebook.

I would like to bridge this gap so that if the user has logged in from the mobile app via facebook and has their facebook token, allow that facebook token to be used as the authentication on the rails app as if they had received it from facebook via the browser.

The end result would be that the mobile app can log a user in via:

1) username/password
or
2) http authentication token
or
3) omniauth (facebook) token

Also, in the case of 3), if the user doesn't yet exist on the rails app, would need to create the user - doing that now already with browser side authentication so there may be nothing more to do.

How can I best accomplish this within the devise construct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我一向站在原地 2024-12-08 17:07:34

刚刚这样做,但从未见过端到端的解决方案。

这解决了第 3. 1 点和第 3. 1 点。 2 可以通过设计轻松完成并在其他地方记录。

将 FB auth 添加到您的 Web 应用程序并不太难,github 上有针对omniauth 和omniauth-facebook 的说明。

我相信以下内容是独立的,没有进行omniauth-facebook集成,如果你想这样做的话。这与其他方法类似。我的想法是尝试尽可能接近地使用设计模型。

您将需要 fb_graph gem。

在移动客户端上,您可以适当地使用 FB 进行身份验证,并将返回的访问令牌放入 http 请求的标头中。我使用了标头 fb_access_token。 就像基本身份验证一样,您需要通过 SSL 发送此信息以避免嗅探令牌。使用标头允许我在不更改请求的情况下交换基本身份验证和 FB 身份验证,但您可以使用参数(如果您愿意)。

该解决方案实现了基于设计的可验证典狱长策略的典狱长策略。此处的区别在于,该策略使用名为 fb_access_token 的 HTTP 标头,其中包含使用移动应用程序检索的 facebook 访问令牌字符串。

一旦了解了这一点,代码就非常简单了。

在 config/initializers 目录中的文件中,添加以下内容。我碰巧调用了我的 fb_api_strategy.rb:

# authentication strategy to support API authentication over the webservice
# via facebook

require 'devise/strategies/database_authenticatable'
require 'fb_graph'
require 'warden'

module Devise
  module Strategies
    class FbMobileDatabaseAuthenticatable < Authenticatable
  def valid?
    # if we have headers with the facebook access key
    !!request.headers["fb_access_token"]
  end

  def authenticate!
    token = request.headers["fb_access_token"]
    fbuser = FbGraph::User.me(token)
    fbuser = fbuser.fetch

    user = User.find_for_facebook_mobile_client(fbuser.email)

    # this either creates a new user for the valid FB account, or attaches
    # this session to an existing user that has the same email as the FB account

    if !!user && validate(user) { true }
      user.after_database_authentication
      success!(user)
    elsif !halted? || !user
      fail(:invalid)
        end
      end
    end
  end
end

Warden::Strategies.add(:fb_database_authenticatable,
                       Devise::Strategies::FbMobileDatabaseAuthenticatable)

在 config/initializers 中,将以下内容添加到 devise.rb:

  config.warden do |manager|
    manager.default_strategies(:scope => :user).unshift :fb_database_authenticatable
  end

要允许您根据 FB 电子邮件创建用户或查找现有用户,请将以下内容添加到您的用户模型中:

  def self.find_for_facebook_mobile_client(fb_email)
    if user = User.where(:email => fb_email).first
      user
    else
      User.create!(:email => fb_email, :password => Devise.friendly_token[0,20])
    end
  end

I我认为 fb_database_authenticatable 不是一个准确的名称,但我将其作为读者的练习。另一个练习是缓存/存储 FB 访问令牌,并且可能避免每次调用时对 FB 的 RT。您应该注意,如果您在两侧都进行 FB 身份验证,则移动应用程序和 Rails 应用程序的访问令牌将会不同,我怀疑大多数人都会想要这样做。这可能会影响您的缓存方案。

我认为这样就可以了——快乐编码。

Just did this, but never saw an end-to-end solution.

This addresses point 3. 1 & 2 are easily accomplished with devise and documented elsewhere.

Not too hard to add FB auth to your web app, the instructions are on github for omniauth and omniauth-facebook.

I believe the following stands alone, without doing the omniauth-facebook integration, if you want to do it that way. This is similar to other approaches out there. My idea was to attempt to use the devise model as closely as I could.

You'll need the fb_graph gem.

On the mobile client, you authenticate with FB appropriately and put the returned access token in the header of your http requests. I used the header fb_access_token. Just like basic auth, you'll want to send this over SSL to avoid sniffing of the token. Using the header allows me to interchange basic auth and FB auth without changing the requests, but you could use a parameter if you prefer.

This solution implements a warden strategy which is based off of the devise Authenticatable warden strategy. The difference here is the fact that this strategy utilizes an HTTP header called fb_access_token containing the facebook access token string that was retrieved using the mobile application.

Once you know this, the code is pretty straightforward.

In a file, in the config/initializers directory, add the following. I happened to call mine fb_api_strategy.rb:

# authentication strategy to support API authentication over the webservice
# via facebook

require 'devise/strategies/database_authenticatable'
require 'fb_graph'
require 'warden'

module Devise
  module Strategies
    class FbMobileDatabaseAuthenticatable < Authenticatable
  def valid?
    # if we have headers with the facebook access key
    !!request.headers["fb_access_token"]
  end

  def authenticate!
    token = request.headers["fb_access_token"]
    fbuser = FbGraph::User.me(token)
    fbuser = fbuser.fetch

    user = User.find_for_facebook_mobile_client(fbuser.email)

    # this either creates a new user for the valid FB account, or attaches
    # this session to an existing user that has the same email as the FB account

    if !!user && validate(user) { true }
      user.after_database_authentication
      success!(user)
    elsif !halted? || !user
      fail(:invalid)
        end
      end
    end
  end
end

Warden::Strategies.add(:fb_database_authenticatable,
                       Devise::Strategies::FbMobileDatabaseAuthenticatable)

In config/initializers, add the following to devise.rb:

  config.warden do |manager|
    manager.default_strategies(:scope => :user).unshift :fb_database_authenticatable
  end

To allow you to either create a user or find an existing user based on the FB email, add the following to your user model:

  def self.find_for_facebook_mobile_client(fb_email)
    if user = User.where(:email => fb_email).first
      user
    else
      User.create!(:email => fb_email, :password => Devise.friendly_token[0,20])
    end
  end

I don't think fb_database_authenticatable is an accurate name, but I'll leave that as an exercise for the reader. Another exercise is caching/storing the FB access token, and perhaps avoiding the RT to FB with each call. You should note that the access token from the the mobile app and the rails app will be different if you do FB authentication on both sides, which I suspect most people will want to do. This probably impacts your caching scheme.

I think that does it - happy coding.

起风了 2024-12-08 17:07:34

如果您在 Xcode 4.3.2 中设置请求标头
你可以使用:

[request setValue:@"12345" forHTTPHeaderField:@"fbaccesstoken"];

但你不能使用:

[request setValue:@"12345" forHTTPHeaderField:@"fb_access_token"]; // does NOT get set

If you are setting request headers in xcode 4.3.2
you could use:

[request setValue:@"12345" forHTTPHeaderField:@"fbaccesstoken"];

but you cannot use:

[request setValue:@"12345" forHTTPHeaderField:@"fb_access_token"]; // does NOT get set
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文