Вопрос по ruby-on-rails, ruby – Аутентификация Rails между приложениями / серверами

28

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

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

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

First question: Это жизнеспособное решение?

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

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

Есть несколькоOauth Servers это может помочь в реализации такого сценария. Thomas Klemm

Ваш Ответ

3   ответа
20

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

Основным преимуществом OAuth является то, что онallows users to give 3rd party apps access to their account without disclosing their password to the 3rd party, Если вы серьезно не обеспечиваете такую совместимость, то OAuth, вероятно, излишне.

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

For Single Sign On

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

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

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

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

For Internal API calls

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

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

Этот ответ не "предполагает" что все серверы находятся в одном домене, это прямо указывает на этот факт (в разделе «Для единого входа»). Если серверы распределены по разным доменам, вам нужно будет поискать более сложные решения, такие как OAuth. или SAML-SSO.
Это предполагает, что все домены имеют общий домен tld / subdomain. А как насчет разных tlds?
Да, при реализации полного решения единого входа очень многое нужно спроектировать. Создание централизованной службы аутентификации, вероятно, является хорошим началом, но оно выходит за рамки ответа на StackOverflow ... вероятно, больше похоже на книгу О'Рейли.
Совместное использование идентификатора сеанса кажется хорошим началом единого входа, но на этом все заканчивается. Здесь большое количество деталей реализации оставлено здесь. Как приложение аутентифицируется при входе в систему? Как приложение узнает о возможностях вошедшего в систему пользователя?
3

связанная с желанием поделиться данными сеанса между Rails и приложением Erlang. Моим решением было написатьRack::Session::Abstract::ID класс, который хранил сессии в Redis как хеш-значения. Это не вызывает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 вашего пользователя.

4

предложенное Джереми Грином на Octolabs во время RailsConf 2014 года.

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

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

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

Похожие вопросы