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_password 功能 我相信 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 MultiStep 订单的最佳方法
对像 MERN Stack 这样的 Web 和 api 解决方案进行身份验证和授权的最佳方式是啥?
Heroku上的现有Ruby on Rails Web应用程序(PostgreSQL),Devise身份验证,需要为移动支持添加Rails API