Использование authlogic_api для доступа к Rails REST API

Я пишу внутренний API Rails для игры Steam, доступ к которой осуществляется только через вызовы REST, поэтому аутентификация пользователя не требуется. Я пытаюсь реализовать подключаемый модуль authlogic_api для Authlogic gem, который использует механизм api_key/signature для ограничения доступа. Я реализовал модели ApplicationSession и ApplicationAccount, как описано в rdocs, но не знаю, как изменить мой ApplicationController, чтобы ограничить доступ.

Судя по исходному коду, подключаемый модуль authlogic_api изменяет модули ActsAsAuthentic и Session от Authlogic. Но поскольку это, по сути, аутентификация с «единым доступом», требующая передачи ключа API и подписи при каждом запросе, я не вижу, как сеансы могут быть фактором.

Кто-нибудь успешно реализовал authlogic_api в своих приложениях? Если да, поделитесь своим подходом к настройке ApplicationController?


person zinndesign    schedule 24.06.2010    source источник


Ответы (3)


На самом деле все намного проще. Использование всего этого кода из примера Authlogic несколько излишне — он в основном управляет хранением сведений о сеансе, чего вам не нужно делать для сеанса приложения (также известного как клиент). Сеанс клиента повторно подтверждается при каждом запросе.

Все что тебе нужно это:

модели\клиент.rb

class Client < ActiveRecord::Base
  acts_as_authentic do |config|
  end
end

модели\client_session.rb

class ClientSession < Authlogic::Session::Base
  api_key_param 'app_key'
end

контроллеры\application_controller

before_filter :verify_client

def verify_client
  @client_session = ClientSession.new()
  unless @client_session.save # if client session not successfully created using the api_key and signature, render an error and block the request
    @error = {:description => "Couldn't validate client application."}
    render :template => 'errors/error.xml.builder'
  end
end

Вам также необходимо выполнить миграцию, чтобы создать таблицу клиентов. Не все поля ниже обязательны, но они не помешают.

class CreateClients < ActiveRecord::Migration
  def self.up
    create_table :clients do |t|
      # human fields
      t.string :name
      t.string :owner
      t.string :owner_email
      t.string :owner_phone
      # login fields
      t.string :api_key, :null => false
      t.string :api_secret, :null => false
      t.string :password_salt
      t.string :persistence_token
      t.string :perishable_token
      # automagical fields (courtesy of authlogic & authlogic_api)
      t.integer :failed_login_count
      t.datetime :last_request_at
      t.integer :request_count
      t.string :last_request_ip
      # automagical fields (courtesy of rails)
      t.timestamps
    end
  end

  def self.down
    drop_table :clients
  end
end
person Dave T    schedule 03.10.2010

Возможно, вам не понадобятся накладные расходы Authlogic.

Если вы создаете URL-адрес, который затем отправит клиент, просто добавьте отметку времени истечения срока действия и выполните хеширование (подпись) MD5 для всего URL-адреса, добавив результат в качестве окончательного параметра запроса.

Пожалуйста, добавьте фильтр before_filter к действию контроллера, т. е. метод signed_url, который будет проверять URL-адрес. Этот метод должен получить URL-адрес из объекта запроса. Убедитесь, что срок действия не истек. Удалите подпись из URL-адреса, чтобы поместить ее в ту же форму, которая использовалась для создания исходного URL-адреса, сделайте это и проверьте соответствие. Вуаля.

Срок действия важен, чтобы быть уверенным, что URL нельзя будет повторно использовать позже.

Это отличный метод централизации в качестве альтернативного способа авторизации запросов без входа в систему. Пока вы сгенерировали URL-адрес, он будет действителен до истечения срока действия с любого хоста.

person aceofspades    schedule 26.06.2010
comment
Спасибо за ответ. Однако я не понимаю, как это будет аутентифицировать входящий запрос от действительного клиента? Механизм ключа/подписи API, по крайней мере, требует, чтобы клиент предоставил эти учетные данные. - person zinndesign; 08.07.2010

Решил эту проблему, следуя примеру Authlogic и просто заменив модель ClientAccount для модели пользователя. Итак, в моем контроллере приложений у меня есть:

before_filter :require_client

def require_client
  unless current_client
    store_location
    render :text => 'Authentication failed', :status => 401
    return false
  end
end

def require_no_client
  if current_client
    store_location
    render :text => 'Client session already exists', :status => 401
    return false
  end
end

def current_client_session
  return @current_client_session if defined?(@current_client_session)
  @current_client_session = ClientSession.find
end

def current_client
  return @current_client if defined?(@current_client)
  @current_client = current_client_session && current_client_session.record
end

Модель ClientAccount действует как аутентичная, а модель ClientSession обрабатывает создание и уничтожение сеансов для Authlogic (authenticate_with ClientAccount):

class ClientSessionsController < ApplicationController
  before_filter :require_no_client, :only => [:new, :create]
  before_filter :require_client, :only => :destroy

  def new
    @client_session = ClientSession.new
  end

  def create
    @client_session = ClientSession.new(params[:client_session])
    if @client_session.save
      redirect_back_or_default account_url
    else
      render :action => :new
    end
  end

  def destroy
    current_client_session.destroy
    redirect_back_or_default new_client_session_url
  end
end

Это решение хорошо зарекомендовало себя, поскольку мы можем генерировать разные комбинации ключей/подписей API для разных клиентов, что дает нам дополнительные данные об использовании. Единственная «загвоздка» - это если вы делаете что-то вроде многокомпонентной загрузки файла, поскольку хэш POST использует необработанные данные POST.

person zinndesign    schedule 07.07.2010