Rails api 和本机移动应用程序身份验证

Posted

技术标签:

【中文标题】Rails api 和本机移动应用程序身份验证【英文标题】:Rails api and native mobile app authentication 【发布时间】:2014-03-02 13:33:11 【问题描述】:

我知道有很多关于这个主题的信息,但我找不到任何最新的。 我看到像this one relating to rails and android authentication 这样的主题,但我看到TokenAuthenticatable is now removed from devise。

我的问题很简单:有没有一种使用 Rails 4 对来自原生 Android 和 iPhone 应用程序的用户进行身份验证的好方法?有谁知道提供解决方案的好教程或文章?

Adam Waite 添加赏金:

我刚刚在这个问题上打开了 500 赏金,因为我找不到在任何地方将用户从 ios 应用程序验证到 Rails API 的正确做法。这是我正在考虑做的,但不知道它是否安全?!:

假设我们有一个User 记录。用户注册了一个帐户,该帐户在数据库中创建了一条 User 记录,其中包含 email 列和 password_digest 列。

当用户登录时,我希望该用户在移动应用上保持身份验证,直到明确退出。

我想我们将需要基于令牌的身份验证。我可能会在创建 User 时创建一个 ApiKey 记录,并将其保存为 User 记录上的关联。

当用户登录/注册时,响应将包含一个 API 令牌(类似于SecureRandom.hex),该令牌将保存在 iOS 钥匙串中,并与所有后续请求一起使用,通过在标头中传递它来验证用户和使用类似的东西来验证它:

before_filter :restrict_access

private

def restrict_access
authenticate_or_request_with_http_token do |token, options|
  ApiKey.exists?(access_token: token)
end

这安全吗?我是否应该在每个请求中刷新令牌并将其包含在响应中?

我还有什么其他选择? Facebook、Twitter 和 Pinterest 之类的网站是做什么的?

我知道 OAuth2.0,但这不是为了授予外部应用程序吗?

是否有一个 gem 可以管理这些?

抱歉,这里完全不确定。

500 到最佳答案。

【问题讨论】:

我的任务终于成功了,我现在有一个 Rails 后端,Android 应用可以注册、登录和注销,无需每次都重新验证。我很快就会做例子。它工作得很好,但我不知道它是否安全,我不擅长那个......所以我等待回复。 我可以在 iOS 上做同样的事情,但和你一样,不知道它是否容易被破解! 也许my answer to this other question 会有所帮助。 我正在做的是用提到的 apiauth gem Troy 修改这个github.com/danahartweg/authenticatable_rest_api 应用程序中的令牌生成。该应用程序具有 Ashitaka 提到的所有步骤。 @agonist_ 你能解释一下你的制作方法吗? 【参考方案1】:

您在正确的轨道上,但用户的令牌应仅用于识别发出请求的用户。您仍然需要某种身份验证,因为正如您推测在每个请求上更改令牌时,黑客可能会拦截数据流,获取令牌,然后在后续请求中“成为”该用户。

通过更改每个请求的令牌,您可以消除拦截问题,但是一旦有人拦截了令牌,他们就可以通过继续拦截它甚至修改响应来进一步利用系统。一种解决方案是使用 HMAC(由 Amazon Web Services 使用)。它是一种算法,可为您的请求提供签名(哈希),该签名对每个请求都是唯一的,不需要更改密钥,并且无法预测未来的请求。

rails 有一个 ruby​​ gem,它在服务器端实现 HMAC,用于签署 HMAC 请求以及在进行服务器到服务器通信时生成它们。对于您的情况的客户端到服务器请求,您需要在 iOS 或 Android 端生成签名并在服务器上对其进行身份验证。

考虑使用ApiAuth gem 在服务器端完成工作。在 iOS 客户端,考虑使用 HBHMAC 库来生成签名。看看 ApiAuth 的具体实现,因为它为数据添加时间戳以防止重放攻击,因此您可能需要在将数据传递给 HBHMAC 之前向数据添加一个字段。

总而言之,使用 HMAC 身份验证将避免中间人攻击和重放攻击,它利用单向哈希算法防止攻击者生成真实请求,即使他们能够拦截有效请求。

【讨论】:

看起来不错,感谢您的回答。在接受之前将等待看看还有什么结果,谢谢【参考方案2】:

我遇到过这个问题,我是一名 API 开发人员。你可以用令牌和自定义授权来做这件事,但我会告诉你我们如何处理我们的应用程序,它为六位数的用户提供服务。

至少对于 iOS,设备会为您处理会话,这意味着如果 iOS 应用上的用户使用参数向 /users/sign_in 发出 POST 请求

user:  
  password: 'mypassword',
  email: 'testuser@example.com',
  remember_me: true # optional

iOS 设备将为您安全持久地存储会话。

现在,如果您想使用 OAuth 2 路线,我实际上为 rails 4 维护了一个名为 OAuth 2 providable 的 gem,我在其中添加了一个非常酷的功能,允许您让用户通过“授权”屏幕,因为显然,如果您开发了软件,则不需要用户确认他们信任您。

如果您决定使用 OAuth 2,则需要使用所谓的隐式访问令牌。 This is the long and very boring OAuth2 spec for that

rails 4 项目可以在 github 上找到 https://github.com/bwheeler96/devise-oauth2-provider-rails4

如果您不在 Rails 4 上,则可以使用原始 gem https://github.com/socialcast/devise_oauth2_providable

顺便说一句,gem 需要工作,所以如果有人在阅读本文并希望帮助它变得更好,请务必 fork this repository

【讨论】:

【参考方案3】:

我研究的解决方案要点。随意编辑、更正、无效等。

SessionsController < ApplicationController
  skip_before_filter :authenticate_user, :only => [:create]
  def create
    user = User.where("username = ? OR email = ?", params[:username_or_email], params[:username_or_email]).first
    if user && user.authenticate(params[:password])
      api_key = user.find_api_key
      if !api_key.secret_key || api_key.is_expired?
        api_key.set_expiry_date
        api_key.generate_secret_key
      end
      api_key.save
      render json: api_key, status: 201     
    else
      status: 401
    end
  end

注意 ApiAuth.authentic 了吗?方法和请求对象。请求必须在客户端使用 HMAC 算法进行签名。

ApplicationController < ActionController::Base
  respond_to :json
  force_ssl
  protect_from_forgery with: :null_session 
  before_filter :authenticate_user
  private
  def authenticate_user
    if authenticate_user_from_secret_key
      return true
    else
      head :unauthorized 
    end
  end
  def authenticate_user_from_secret_key
    userid = ApiAuth.access_id(request)
    currentuser = userid && User.find_by_id(userid)
    if ApiAuth.authentic?(request, currentuser.find_api_key.secret_key)
      return true
    else
      return false
    end
    false
  end

用户创建/注册

UsersController < ApplicationController
  skip_before_filter :authenticate_user, :only => [:create]
  def create
      user = User.create(user_params)
      if !user.new_record?
        render json: user.find_apit_key, status: 201

      else
       # error
      end
  end

API 密钥模型。类似于 #352 railscast 中的 api 密钥模型,唯一的区别是 ApiAuth 密钥生成。

class ApiKey < ActiveRecord::Base
  before_create :generate_secret_key, :set_expiry_date
  belongs_to :user   
  def generate_secret_key
    begin
    self.secret_key = ApiAuth.generate_secret_key
    end while self.class.exists?(secret_key: secret_key)
  end

用户模型。

class User < ActiveRecord::Base
  has_secure_password
  before_save :ensure_api_key 
  has_many :api_keys 
  def find_api_key
   self.api_keys.active.ios.first_or_create
  end

在客户端,必须使用 HMAC 算法对请求进行签名。

代码来自: [SHA1 HMAC 密钥生成/认证]https://github.com/mgomes/api_auth [控制器和型号]https://github.com/danahartweg/authenticatable_rest_api

【讨论】:

【参考方案4】:

如果你想在 ruby​​ on rails 中使用 OAuth2.0,你会使用 Doorkeeper,你可以在这里看到一个例子(不是免费的):

http://railscasts.com/episodes/353-oauth-with-doorkeeper

但是您可以使用带有 SecureRandom.hex 的令牌,这里有一个示例(不是免费的)(第 6 级):

https://www.codeschool.com/courses/surviving-apis-with-rails

希望我的回答对你有帮助!

【讨论】:

以上是关于Rails api 和本机移动应用程序身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Rails API:实现身份验证的最佳方式?

使用 Devise 从 Rails 上的 json api 进行身份验证

SOA:Rails 多个客户端的用户身份验证和 api 授权

使用 JWT 和刷新令牌对移动应用程序进行身份验证

使用 cookie/会话进行移动应用程序身份验证?

rails 3中的api身份验证