Rails API: лучший способ реализовать аутентификацию?
Я пишу приложение Rails 4, которое будет предоставлять API для мобильного приложения, которое еще не разработано. Пользователи будут аутентифицироваться с помощью электронной почты и пароля из мобильного приложения.
В то время как я нашел довольно много информации по этой теме. Трудно определить, что является устаревшим или неоптимальным. Я читал о HTTP Basic Auth, который не кажется слишком безопасным, и HTTP Token-based Auth, но я не уверен, как сочетать это с обычной проверкой подлинности по электронной почте и паролю (я использую Devise by подобно тому как).
Я просто хотел бы знать, какова текущая лучшая практика по реализации этого, так что я буду уверен, что иду правильным путем.
4 ответа:
Важным моментом с точки зрения безопасности является обмен электронной почты и пароля пользователя на токен один раз, а затем использовать этот токен для последующих запросов. Это происходит потому, что:
- Вы не хотите, чтобы клиентское приложение несло ответственность за сохранение пароля пользователя, когда ошибка или атака могут привести к его утечке; и
- выданный сервером токен дает вам (и вашим пользователям) возможность истечь срок действия токена, если это необходимо, например, чтобы заблокировать украденное устройство или заблокировать непослушный клиент 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, но то, что лучше всего подходит для вашего проекта!