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


78

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

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

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


1
不知道具体细节,我的想法是OAuth2。使用门卫或oauth2宝石。
2015年

Answers:


49

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

  1. 您不希望客户端应用程序负责保留用户的密码,否则可能会导致错误或攻击而导致用户密码泄漏;和
  2. 服务器颁发的令牌使您(和您的用户)能够在必要时使令牌过期,例如,锁定被盗的设备或阻止行为异常的API客户端。

有多种方法可以实现不同级别的复杂性。

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


谢谢!这是我需要了解的。
Roma149

除了设计令牌之外,您还可以使用设备令牌。该答案的设备令牌可以帮助您正确识别设备,如果其他设备访问您的网站,则可能会有所帮助。
duykhoa 2015年

5

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

应用程序/模型/问题/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已被弃用。
Kelsey Hannan

4

@ Roma149这更多是个人喜好,但是大多数刚入门的人都使用Devise,因为它是最简单的IMO。OAuth2也是一个不错的选择。更重要的是,您可以随时转到Ruby Toolbox

那里有很多关于宝石的好信息,它们甚至可以告诉您宝石的年龄和受欢迎程度。这也将使您能够区分社区现在真正在偷偷摸摸的宝石还是过时的宝石。

请记住,在Ruby和Ruby On Rails中,并非总是更好的选择,而是最适合您的项目的东西!


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.