Единый выход из нескольких приложений от поставщика Doorkeeper

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

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

Это мой контроллер сеанса связи от моего поставщика Doorkeeper.

class SessionsController < ApplicationController
  def new
    redirect_to root_path if current_user
    session[:return_to] = params[:return_to] if params[:return_to]
  end

  def create
    user = User.find_by_email(params[:email])
    if user && user.authenticate(params[:password])
      session[:user_id] = user.id
      if session[:return_to]
        redirect_to session[:return_to]
        session[:return_to] = nil
      else
        redirect_to root_path

      end
    else
      flash.now.alert = "Email or password is invalid"
      render "new"
    end
  end

  def destroy
    session[:user_id] = nil
    flash[:alert] = "Sign Out successfully"
    redirect_to new_session_path
  end
end

Это мой контроллер сеанса из одного из моих приложений:

    class SessionsController < ApplicationController
  def create
    auth = request.env["omniauth.auth"]
    user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
    session[:user_id] = user.id
    session[:access_token] = auth["credentials"]["token"]
    redirect_to root_url
  end

  def destroy
    session[:user_id] = nil
    session[:access_token] = nil
    redirect_to root_url
  end
end

Я написал собственную аутентификацию пользователя для приложения поставщика Doorkeeper, но я использовал Devise для своего приложения, подключенного к моему провайдеру Doorkepeer.

В настоящий момент, когда я выхожу из приложения Doorkeeper, я все еще вхожу в аккаунт в другом приложении. Итак, как мне сделать, чтобы я выходил из Doorkeeper, и это заставит меня выходить из всех приложений?

Ответ 1

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

Ответ 3

Как я вижу, вы можете синхронизировать состояния между приложениями либо путем относительно сложного обмена вызовами API (подверженные сетевым ошибкам, "одно из моих приложений просто перезапускало",... и т.д.), либо путем внедрения общее хранилище, лучшим вариантом, вероятно, является общий memcached или общий сервер redis, который будет хранить токены доступа для ваших идентификаторов пользователей.

Один из способов решения этой проблемы - переопределить session в ApplicationController всех ваших клиентских приложений для привратника и заставить их пинговать совместное хранилище, когда что-то хочет получить или установить :access_token.

Заметьте, что я не поклонник хеш [] и []= переопределения, потому что он нарушает принцип наименьшего удивления, но Я считаю, что это лучший подход в этом случае.

Я даю вам пример кода для переопределения экземпляра session, чтобы сделать именно это: https://gist.github.com/bbozo/f5c28fe9bd804dff0af8 с помощью Dalli memcached client, что нужно отметить:

  • Подход Redis так же прост (https://github.com/redis/redis-rb),
  • есть много вариантов "бесплатно начать" для обоих, здесь любимый героем для memcached: https://www.memcachier.com/pricing (как вы можете сказать, LOT 80-байтных токенов аутентификации вписывается в 25 МБ: P)

Обратите внимание, что я не уверен на 100%, что переопределение методов экземпляра не происходит с нечеткой рекурсией поиска метода, поэтому, если у вас есть контроль над созданием session, вероятно, безопасно просто создать класс, который наследует из HashWithIndifferentAccess с 2-мя переопределениями из gist, а затем создайте экземпляр вместо стандартного хэш-класса, но на самом деле не беспокоитесь об этом, если не ожидаете какого-то действительно серьезного трафика.