Ruby-on-rails Rails API:实现身份验证的最佳方式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30038475/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:13:44  来源:igfitidea点击:

Rails API : Best way to implement authentication?

ruby-on-railsruby-on-rails-4rails-api

提问by Roma149

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.

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

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).

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

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.

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

采纳答案by Matt Brictson

The important point, from a security perspective, is to exchange the user's email and password for a token once, and then use that token for subsequent requests. This is because:

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

  1. You don't want the client app to be responsible for holding onto the user's password, where a bug or attack could cause it to be leaked; and
  2. A server-issued token gives you (and your users) the ability to expire a token if necessary, e.g. to lock out a stolen device or block a misbehaving API client.
  1. 您不希望客户端应用程序负责保留用户的密码,因为错误或攻击可能导致密码泄露;和
  2. 服务器颁发的令牌使您(和您的用户)能够在必要时使令牌过期,例如锁定被盗设备或阻止行为不端的 API 客户端。

There are many ways to accomplish this with varying levels of complexity.

有许多方法可以实现这一点,但复杂程度各不相同。

Here is a tutorial that is very recent and has a thorough walkthrough for creating an API in Rails with token-based authentication (not using Devise, but still relevant to understand the concepts): https://labs.kollegorna.se/blog/2015/04/build-an-api-now/

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

回答by Antarr Byrd

Another option is to include the module below in your devise MODEL and add the auth_token to you table.

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

app/models/concerns/token_authenticable.rb

应用程序/模型/关注点/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

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

Edit: Corrected code-breaking typo

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

回答by The Gugaru

@Roma149 this is more of a personal preference but most people who are just starting out use Devise as it is the easiest IMO. OAuth2 is a good option as well. As a more important note you can always go to The Ruby Toolbox

@Roma149 这更多是个人偏好,但大多数刚开始使用 Devise 的人,因为它是最简单的 IMO。OAuth2 也是一个不错的选择。作为更重要的说明,您可以随时访问The Ruby Toolbox

There is a lot of good information on gems there and they even tell you the age and the popularity of the gem. This will also allow you to differentiate between what gems the community is really geeking out on now or what has gone stale.

那里有很多关于宝石的好信息,他们甚至会告诉您宝石的年龄和受欢迎程度。这也将使您能够区分社区现在真正热衷的宝石或已经过时的宝石。

Remember in Ruby and Ruby On Rails it is not always what is better gem wise but what best fits your project!

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

回答by Zakaria

Tiddlegem provides Devise strategy for token authentication in API-only Ruby on Rails applications. Its main feature is support for multiple tokens per user.

Tiddlegem 为仅 API 的 Ruby on Rails 应用程序中的令牌身份验证提供了设计策略。它的主要特点是支持每个用户多个令牌

https://github.com/adamniedzielski/tiddle

https://github.com/adamniedzielski/tiddle