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

Posted

技术标签:

【中文标题】Rails API:实现身份验证的最佳方式?【英文标题】:Rails API : Best way to implement authentication? 【发布时间】:2015-07-14 07:57:10 【问题描述】:

我正在编写一个 Rails 4 应用程序,它将为尚未开发的移动应用程序公开一个 API。用户将使用来自移动应用的电子邮件和密码进行身份验证。

虽然我找到了很多关于该主题的信息。很难辨别什么是过时的或非最佳的。我读过关于 HTTP 基本身份验证,这似乎不太安全,以及基于 HTTP 令牌的身份验证,但我不确定如何将其与常规电子邮件和密码身份验证相结合(我正在使用 Devise方式)。

我只是想知道如何实现这一点的当前最佳实践是什么,所以我一定会走正确的路。

【问题讨论】:

不知道具体情况,我的想法是OAuth2。使用门卫或 oauth2 gem。 【参考方案1】:

从安全角度来看,重要的一点是将用户的电子邮件和密码交换一次令牌,然后将该令牌用于后续请求。这是因为:

    您不希望客户端应用负责保存用户密码,因为错误或攻击可能导致密码泄露;和 服务器颁发的令牌使您(和您的用户)能够在必要时使令牌过期,例如锁定被盗设备或阻止行为不端的 API 客户端。

有很多方法可以实现这一点,但复杂程度各不相同。

这是一个最新的教程,它对在 Rails 中使用基于令牌的身份验证创建 API 进行了全面的演练(不使用 Devise,但仍然与理解概念相关):https://labs.kollegorna.se/blog/2015/04/build-an-api-now/

【讨论】:

谢谢!这是我需要理解的。 除了设计令牌,您还可以使用设备令牌。设备令牌this answer 可以帮助您正确识别设备,在其他设备访问您的网站时可能会有所帮助。【参考方案2】:

另一种选择是在您的设计模型中包含以下模块并将 auth_token 添加到您的表中。

app/models/concerns/token_authenticable.rb

module TokenAuthenticatable
  extend ActiveSupport::Concern

  included do
    before_save :ensure_auth_token
  end

  module ClassMethods
    def find_by_token(token)
      find_by(auth_token: token)
    end
  end

  def ensure_auth_token
    self.auth_token = generate_auth_token if auth_token.blank?
  end

  private

  def generate_auth_token
    loop do
      token = Devise.friendly_token
      break token unless self.class.exists?(auth_token: token)
    end
  end
end

app/controllers/api/v1/login_controller.rb

...
 def login_user(params)
    if params[:authentication]
      @user = User.find_by(auth_token: params[:authentication])
      if @user.nil?
        render json: err('login user by token failed', ERR_USER_NOT_FOUND), status: :not_found
        event('login_user_by_auth_failed', 'token', params[:authentication])
        return
      else
        render status: :ok, json: @user
        return
      end
    else
      user = user.find_by(email: params[:email])
      if user.nil?
        event('login_user_failed_not_found', 'user_email', params[:email])
        render json: err("login user not found #params[:email]", ERR_USER_NOT_FOUND), status: :not_found
        return
      end
      if user.access_locked?
        event('login_user_blocked', 'user_id', user.id)
        render json: err("login user account is locked : #user.id", ERR_USER_LOCKED), status: :unauthorized
        return
      end
      unless user.try(:valid_password?, params[:password])
        event("login_user_password_does_not_match #user.id", 'user_id',  user.id)
        render json: err('login user password does not match', ERR_PASSWORD_NOT_MATCH), status: :unauthorized
        return
      end
      event('login_user_succeeded', 'user_id', user.id)
      @user= user
      if @user.save
        response.headers['authentication'] = @user.auth_token
        render status: :ok, json: @user
        return
      else
        render json: @user.errors, status: :unprocessable_entity
        return
      end
    end
  end
...

编辑:更正了破坏代码的错字

【讨论】:

另外看看 rails 的 has_secured_pa​​ssword 功能 我相信 token_authenticable 已被弃用。【参考方案3】:

@Roma149 这更多是个人喜好,但大多数刚开始使用 Devise 的人,因为它是最简单的 IMO。 OAuth2 也是一个不错的选择。 作为更重要的说明,您可以随时前往The Ruby Toolbox

那里有很多关于宝石的好信息,它们甚至会告诉您宝石的年龄和受欢迎程度。这还可以让您区分社区现在真正在寻找什么宝石,或者什么已经过时了。

请记住,在 Ruby 和 Ruby On Rails 中,并不总是对 gem 更好,而是最适合您的项目!

【讨论】:

【参考方案4】:

Tiddle gem 为仅 API 的 Ruby on Rails 应用程序中的令牌身份验证提供设计策略。它的主要特点是支持每个用户使用多个令牌

https://github.com/adamniedzielski/tiddle

【讨论】:

以上是关于Rails API:实现身份验证的最佳方式?的主要内容,如果未能解决你的问题,请参考以下文章

rails 3中的api身份验证

对 Web 服务进行身份验证的最佳方式是啥

无需身份验证的安全 Rails 3 MultiStep 订单的最佳方法

对像 MERN Stack 这样的 Web 和 api 解决方案进行身份验证和授权的最佳方式是啥?

Heroku上的现有Ruby on Rails Web应用程序(PostgreSQL),Devise身份验证,需要为移动支持添加Rails API

安全验证必备——语音验证码短信 API