Rails api и аутентификация собственного мобильного приложения
Я знаю, что есть много информации об этой теме, но я не могу найти что-то актуальное.
Я вижу такие темы, как этот, относящийся к рельсам и андроидной аутентификации, но я вижу, что TokenAuthenticatable
теперь удаляется из приложения.
Мой вопрос прост: есть ли хороший способ аутентифицировать пользователей из родных приложений для Android и iPhone с помощью Rails 4? Кто-нибудь знает хорошие учебники или статьи, которые предоставляют решение?
Адам Уайт Добавляет награду:
Я только что открыл 500 бонусов по этому вопросу, потому что я не могу найти правильную практику для аутентификации пользователя из приложения iOS в Rails API в любом месте. Это то, что я рассматривал, но понятия не имею, безопасно это или нет?!:
Предположим, что у нас есть запись User
. Пользователь зарегистрировался для учетной записи, которая создала запись User
в базе данных с столбцом email
и столбцом password_digest
.
Когда пользователь подписывается, я хотел бы, чтобы этот пользователь оставался аутентифицированным в мобильном приложении до явного подписания.
Я предполагаю, что нам понадобится аутентификация на основе токенов. Я бы, возможно, создал запись ApiKey при создании User
и сохранил ее как ассоциацию в записи User
.
Когда пользователь подписывается в/вверх, ответ будет содержать токен API (что-то вроде SecureRandom.hex
), которое будет сохранено в iOS Keychain и использовано со всеми последующими запросами, чтобы проверить пользователя, передав его в заголовке и проверяя это, используя что-то вроде:
before_filter :restrict_access
private
def restrict_access
authenticate_or_request_with_http_token do |token, options|
ApiKey.exists?(access_token: token)
end
Это безопасно? Должен ли я обновлять токен с каждым запросом и включать его в ответ?
Какие еще варианты у меня есть? Что делают Facebook, Twitter и Pinterest?
Я знаю OAuth2.0, но разве это не для предоставления внешних приложений?
Есть ли камень, который управляет этим?
Извините, совершенно не уверен здесь.
500 к лучшему ответу.
Ответы
Ответ 1
Суть решения из моих исследований. Не стесняйтесь редактировать, исправлять, аннулировать и т.д.
SessionsController < ApplicationController
skip_before_filter :authenticate_user, :only => [:create]
def create
user = User.where("username = ? OR email = ?", params[:username_or_email], params[:username_or_email]).first
if user && user.authenticate(params[:password])
api_key = user.find_api_key
if !api_key.secret_key || api_key.is_expired?
api_key.set_expiry_date
api_key.generate_secret_key
end
api_key.save
render json: api_key, status: 201
else
status: 401
end
end
Обратите внимание на ApiAuth.authentic? метод и объект запроса. Запрос должен быть подписан с алгоритмом HMAC на клиенте.
ApplicationController < ActionController::Base
respond_to :json
force_ssl
protect_from_forgery with: :null_session
before_filter :authenticate_user
private
def authenticate_user
if authenticate_user_from_secret_key
return true
else
head :unauthorized
end
end
def authenticate_user_from_secret_key
userid = ApiAuth.access_id(request)
currentuser = userid && User.find_by_id(userid)
if ApiAuth.authentic?(request, currentuser.find_api_key.secret_key)
return true
else
return false
end
false
end
Создание/регистрация пользователей
UsersController < ApplicationController
skip_before_filter :authenticate_user, :only => [:create]
def create
user = User.create(user_params)
if !user.new_record?
render json: user.find_apit_key, status: 201
else
# error
end
end
Модель ключа Api. Как и в ключевой модели api в # 352, railscast имеет только различие в генерации ключей ApiAuth.
class ApiKey < ActiveRecord::Base
before_create :generate_secret_key, :set_expiry_date
belongs_to :user
def generate_secret_key
begin
self.secret_key = ApiAuth.generate_secret_key
end while self.class.exists?(secret_key: secret_key)
end
Модель пользователя.
class User < ActiveRecord::Base
has_secure_password
before_save :ensure_api_key
has_many :api_keys
def find_api_key
self.api_keys.active.ios.first_or_create
end
На клиентской стороне алгоритм HMAC должен использоваться для подписи запросов.
Код от:
[SHA1 HMAC Генерация ключей/аутентификация] https://github.com/mgomes/api_auth
[Контроллеры и модели] https://github.com/danahartweg/authenticatable_rest_api
Ответ 2
Вы находитесь на правильном пути, но токен пользователя должен использоваться только для определения того, какой пользователь выполняет запрос. Вам все еще нужна какая-то аутентификация, поскольку, поскольку вы спекулируете с изменением токена по каждому запросу, хакер может перехватить поток данных, получить токен и затем "быть" этим пользователем в последующих запросах.
Изменяя токен в каждом запросе, вы устраняете проблему перехвата, но как только кто-то перехватил токен, он может впоследствии использовать систему, продолжая ее перехватывать и даже модифицируя ответ. Одним из решений этого является использование HMAC (который используется веб-службами Amazon). Это алгоритм, который обеспечивает подпись (хэш) для вашего запроса, который является уникальным для каждого запроса, не требует изменения ключа и не может быть предсказан для будущих запросов.
Существует рубиновая жемчужина для рельсов, которая реализует HMAC на стороне сервера для подписания запросов HMAC, а также генерирует их при взаимодействии между серверами. Для запросов "клиент-сервер", как в вашем случае, вам необходимо сгенерировать подпись на стороне iOS или Android и аутентифицировать их на сервере.
Рассмотрим камень ApiAuth, чтобы выполнить работу на стороне сервера. На стороне клиента iOS рассмотрите библиотеку HBHMAC для генерации подписи. Взгляните на конкретную реализацию ApiAuth, поскольку она добавляет временную метку к данным для предотвращения повторных атак, поэтому вам может понадобиться добавить поле к вашим данным, прежде чем передавать его в HBHMAC.
В заключение, использование HMAC-аутентификации позволит избежать нападений в середине и повторных атак, используя алгоритм одностороннего хеширования, который предотвращает создание аутентификационных запросов злоумышленниками, даже если они могут перехватывать действительные запросы.
Ответ 3
У меня была эта проблема, я разработчик API. Вы могли сделать это с помощью токенов и настраиваемой авторизации, но я расскажу вам, что мы делаем с нашим приложением, которое обслуживает пользователей в шестизначной цифре.
Как минимум для iOS, устройство будет обрабатывать сеансы для вас, а это означает, что если пользователь в приложении iOS делает запрос POST на /users/sign_in
с параметрами
user: {
password: 'mypassword',
email: '[email protected]',
remember_me: true # optional
}
устройство iOS будет хранить сеанс для вас безопасно и настойчиво.
Теперь, если вы хотите пойти по маршруту OAuth 2, я фактически поддерживаю жемчужину для рельсов 4 под названием OAuth 2, которые я добавил довольно классную функцию, которая позволяет вам пройти через экран авторизации, потому что, очевидно, если вы разработали программное обеспечение, вам не нужен пользователь, чтобы подтвердить, что они вам доверяют.
Если вы решите использовать OAuth 2, вам нужно будет использовать то, что называется неявным токеном доступа.
Это длинная и очень скучная спецификация OAuth2 для этого
Проект рельсов 4 можно найти на github
https://github.com/bwheeler96/devise-oauth2-provider-rails4
Если вы не на рельсах 4, вы можете использовать оригинальный камень
https://github.com/socialcast/devise_oauth2_providable
Кстати, драгоценный камень нуждается в работе, поэтому, если кто-нибудь читает это, кто хочет помочь сделать его лучше, пожалуйста, непременно fork этот репозиторий
Ответ 4
Если вы хотите использовать OAuth2.0 в рубине на рельсах, вы будете использовать Doorkeeper, здесь вы можете увидеть пример (не бесплатный):
http://railscasts.com/episodes/353-oauth-with-doorkeeper
Но вы можете использовать токен с SecureRandom.hex, пример (не бесплатный) для этого здесь (на уровне 6):
https://www.codeschool.com/courses/surviving-apis-with-rails
Я надеюсь, что мой ответ поможет вам!