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

Rom*_*149 76 ruby-on-rails rails-api ruby-on-rails-4

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

虽然我已经找到了很多关于这个主题的信息.很难看出什么是过时的或非最佳的.我已经阅读了HTTP Basic Auth,它看起来似乎不太安全,以及基于HTTP令牌的Auth,但我不确定如何将它与常规电子邮件和密码认证结合起来(我正在使用Devise by方式).

我想知道目前关于如何实现这一目标的最佳实践,所以我一定会采取正确的方式.

Mat*_*son 48

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

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

有许多方法可以通过不同的复杂程度来实现这一目标.

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


Ant*_*yrd 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
Run Code Online (Sandbox Code Playgroud)

应用程序/控制器/ 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
...
Run Code Online (Sandbox Code Playgroud)

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