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

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

虽然我找到了不少关于这个话题的信息。很难分辨什么是过时的,什么是不理想的。我读过 HTTP Basic Auth,它似乎不太安全,以及 HTTP Token-based Auth,但我不确定如何将它与常规的电子邮件和密码认证结合起来(顺便说一下,我正在使用 Devise)。

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

42588 次浏览

@ Roma149这更多的是个人偏好,但大多数刚刚开始使用 Devise 的人认为它是最简单的 IMO。OAuth2也是一个不错的选择。 作为一个更重要的注意事项,你总是可以去 红宝石工具箱

那里有很多关于宝石的好信息,他们甚至告诉你宝石的年龄和流行程度。这也将允许您区分哪些是社区现在真正喜欢的珠宝,哪些已经过时了。

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

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

  1. 您不希望客户端应用程序负责保存用户的密码,因为一个 bug 或攻击可能会导致密码泄露;
  2. 服务器发布的令牌使您(和您的用户)能够在必要时使令牌过期,例如锁定被盗设备或阻塞行为不当的 API 客户端。

有许多不同复杂程度的方法可以实现这一点。

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

另一种选择是将下面的模块包含在您的设计 MODEL 中,并将 auth _ token 添加到您的表中。

应用程序/模型/关注点/令牌 _ 可验证的. 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/controller/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
...

编辑: 纠正代码破译输入错误

Tiddle gem 为 API-only Ruby on Rails 应用程序中的令牌认证提供了 Devise 策略,其主要特性是 支持每个用户使用多个令牌

Https://github.com/adamniedzielski/tiddle