Rails API: лучший способ реализовать аутентификацию?


Я пишу приложение Rails 4, которое будет предоставлять API для мобильного приложения, которое еще не разработано. Пользователи будут аутентифицироваться с помощью электронной почты и пароля из мобильного приложения.

В то время как я нашел довольно много информации по этой теме. Трудно определить, что является устаревшим или неоптимальным. Я читал о HTTP Basic Auth, который не кажется слишком безопасным, и HTTP Token-based Auth, но я не уверен, как сочетать это с обычной проверкой подлинности по электронной почте и паролю (я использую Devise by подобно тому как).

Я просто хотел бы знать, какова текущая лучшая практика по реализации этого, так что я буду уверен, что иду правильным путем.

4 71

4 ответа:

Важным моментом с точки зрения безопасности является обмен электронной почты и пароля пользователя на токен один раз, а затем использовать этот токен для последующих запросов. Это происходит потому, что:

  1. Вы не хотите, чтобы клиентское приложение несло ответственность за сохранение пароля пользователя, когда ошибка или атака могут привести к его утечке; и
  2. выданный сервером токен дает вам (и вашим пользователям) возможность истечь срок действия токена, если это необходимо, например, чтобы заблокировать украденное устройство или заблокировать непослушный клиент API.

Существует множество способов достижения этой цели с различными уровнями сложности.

Вот учебник, который является очень недавним и содержит подробное пошаговое руководство по созданию API в Rails с аутентификацией на основе маркеров (не используя Devise, но все еще релевантный для понимания концепций): https://labs.kollegorna.se/blog/2015/04/build-an-api-now/

Другой вариант-включить модуль ниже в вашу модель devise и добавить 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
...

Правка: исправлена кодовая опечатка

@Roma149 это скорее личное предпочтение, но большинство людей, которые только начинают использовать Devise, так как это самый простой IMO. OAuth2 также является хорошим вариантом. В качестве более важного замечания вы всегда можете перейти к Ruby Toolbox

Там есть много хорошей информации о драгоценных камнях, и они даже говорят вам о возрасте и популярности камня. Это также позволит вам различать, какие драгоценные камни сообщество действительно выискивает сейчас или что ушло несвежий.

Помните, что в Ruby и Ruby On Rails не всегда то, что лучше gem wise, но то, что лучше всего подходит для вашего проекта!

Tiddle gem предоставляет стратегию разработки для аутентификации токенов в приложениях Ruby on Rails только для API. Его главной особенностью является поддержка нескольких токенов на одного пользователя.

Https://github.com/adamniedzielski/tiddle