Rails API : Best way to implement authentication?

时间:2015-05-04 19:32:53

标签: ruby-on-rails ruby-on-rails-4 rails-api

I'm writing a Rails 4 app that will expose an API for a mobile app that's yet to be developed. Users will authenticate using an e-mail and password from the mobile app.

While I've found quite a bit of information on the topic. It's hard to discern what's dated or non-optimal. I've read about HTTP Basic Auth, which doesn't seem too secure, and HTTP Token-based Auth, but I'm not sure on how to couple that with regular e-mail and password authentication (I'm using Devise by the way).

I'd just like to know what's the current best practice on how to implement this, so I'll be sure to be going the right way.

4 个答案:

答案 0 :(得分:47)

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

  1. 您不希望客户端应用程序负责保留用户的密码,其中错误或攻击可能导致其泄露;和
  2. 服务器颁发的令牌可让您(和您的用户)在必要时使令牌过期,例如:锁定被盗设备或阻止行为不端的API客户端。
  3. 有很多方法可以通过不同程度的复杂性来实现这一目标。

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

答案 1 :(得分: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

应用程序/控制器/ 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
...

编辑:纠正了破译错误的错误

答案 2 :(得分:4)

@ Roma149这更多是个人偏好,但大多数刚开始使用Devise的人都是最容易的IMO。 OAuth2也是一个不错的选择。 更重要的是,您可以随时转到The Ruby Toolbox

那里有很多关于宝石的好信息,他们甚至会告诉你宝石的年龄和受欢迎程度。这也可以让你区分社区现在正在寻找什么样的宝石或者过时的东西。

请记住,在Ruby和Ruby On Rails中,并不总是更好的宝石,但最适合您的项目的是什么!

答案 3 :(得分:3)

Tiddle gem在仅限API的Ruby on Rails应用程序中为令牌身份验证提供Devise策略。它的主要功能是支持每个用户的多个令牌

https://github.com/adamniedzielski/tiddle