Подтвердить что ты не робот

Аутентификация Rails через приложения/серверы

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

Скажите пример Facebook:
a) A MainApp, который позволяет пользователю иметь стену, сообщения и т.д.
b) A PhotoApp, в котором хранятся фотографии, позволяет пользователю видеть его фотографии и т.д. Это автономное приложение, которое будет иметь REST API, который также может использоваться MainApp.

Я думал об использовании OAuth в качестве решения Single Sign On (как в этом уроке http://blog.joshsoftware.com/2010/12/16/multiple-applications-with-devise-omniauth-and-single-sign-on/), где каждое приложение будет авторизовано через OAuth и получит доступ к текущему сеансу пользователя на основе файла cookie.

Первый вопрос: Является ли это жизнеспособным решением?

Второй вопрос: Я хочу иметь возможность вызывать API PhotoApp на сервере MainApp (а не в браузере пользователя). Как аутентификация будет работать в этой ситуации?

Третий вопрос: Как это работает, если скажу, что у меня была служба, которая использовала node.js?

4b9b3361

Ответ 1

Да, SSO, использующий OAuth, является жизнеспособным решением, но это не самый простой. При создании чего-либо нового OAuth 2.0 - это путь. Стандарты OAuth охватывают множество факторов.

Основное преимущество OAuth заключается в том, что он позволяет пользователям предоставлять сторонним приложениям доступ к своей учетной записи, не раскрывая их пароль третьей стороне. Если вы серьезно не обеспечиваете такую ​​функциональную совместимость, то OAuth, вероятно, будет излишним.

Учитывая сложность, я предлагаю разные пары решений:

Для одиночного входа

Хитрость заключается в совместном использовании cookie идентификатора сеанса между хостами в вашем домене и использовании общего хранилища сеансов (например, ActiveRecordStore или хранилища на основе кеша).

Каждое приложение Rails имеет "секрет", который используется для подписывания файлов cookie. В новых приложениях Rails это находится в /config/initializers/secret_token.rb. Установите один и тот же секретный токен в каждом приложении.

Затем настройте сеанс, чтобы разрешить доступ со всех поддоменов:

AppName::Application.config.session_store :active_record_store, :key => '_app_name_session', :domain => :all

Для вызовов внутреннего API

Используйте общедоступный секрет для аутентификации через HTTPS-соединения. Передайте секрет в значении заголовка "Авторизация".

Вы можете легко использовать общий секрет с другими архитектурами (например, node.js). Просто убедитесь, что вы всегда используете HTTPS, иначе общий секрет можно было бы понюхать в сети.

Ответ 2

Недавно у меня возникла аналогичная проблема, связанная с необходимостью совместного использования данных сеанса между Rails и приложением Erlang. Моим решением было написать класс Rack::Session::Abstract::ID, который хранит сеансы в Redis как hash vaules. Он не вызывает Marshal.dump для типов String. Это позволяет нерубным приложениям использовать некоторые из значений сеанса, если они имеют session_id.

require 'rack/session/abstract/id'

class MaybeMarshalRedisSession < Rack::Session::Abstract::ID

  def initialize(app, options = {})
    @redis  = options.delete(:redis) || Redis.current
    @expiry = options[:expire_after] ||= (60 * 60 * 24)
    @prefix = options[:key] || 'rack.session'
    @session_key = "#{@prefix}:%s"
    super
  end

  def get_session(env, sid)
    sid ||= generate_sid
    session = @redis.hgetall(@session_key % sid)
    session.each_pair do |key, value|
      session[key] = begin
        Marshal.load(value)
      rescue TypeError
        value
      end
    end

    [sid, session]
  end

  def set_session(env, sid, session, options={})
    @redis.multi do
      session.each_pair do |key, value|
        # keep string values bare so other languages can read them
        value = value.is_a?(String) ? value : Marshal.dump(value)
        @redis.hset(@session_key % sid, key, value)
      end
      @redis.expire(@session_key % sid, @expiry)
    end

    sid
  end

  def destroy_session(env, sid, option={})
    @redis.del(@session_key % sid)
    generate_sid unless options[:drop]
  end

end

Вы можете использовать это из рельсов с помощью:

 MyApp::Application.config.session_store MaybeMarshalRedisSession

Из стойки с:

 use MaybeMarshalRedisSession

И из других источников:

redis.hgetall("rack.session:#{session_id}")

Если вы хотите вызвать PhotoApp из вашего MainApp или Node.js, вы можете сделать HTTP-запрос, содержащий ваш cookie сеанса пользователя.

Ответ 3

Вы можете взглянуть на решение сервис-ориентированной архитектуры, предложенное Джереми Грин в Octolabs во время RailsConf 2014 года.

Сообщение в блоге со всеми ресурсами (repos, demos и т.д.) находится здесь: http://www.octolabs.com/so-auth

И видео, которое объясняет все, находится здесь: http://www.youtube.com/watch?v=L1B_HpCW8bs

Этот централизованный SSO - не простая задача, но Джереми отлично поработал над сервис-ориентированной архитектурой и делится тем, как можно объединить эту систему.