从门卫提供商的多个应用程序单点注销

时间:2015-07-30 04:50:08

标签: ruby-on-rails ruby-on-rails-4 omniauth doorkeeper

我使用Doorkeeper作为我的Rails应用程序,并且我试图这样做,当用户从门卫提供商退出时,用户将自动从所有应用程序注销。

默认情况下,当用户从应用中退出时,他仍会在门卫提供商应用中登录。

这是我的门卫提供商的会话控制器。

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提供商应用程序。

目前,当我从我的门卫应用程序退出时,我还在我的其他应用程序上登录。那么如何让我从门卫那里退出,这也会让我从所有应用中退出?

3 个答案:

答案 0 :(得分:4)

您必须从门卫应用程序向每个客户端应用程序发送API调用,告诉他们删除特定用户的会话,或者您需要让您的客户端应用程序定期查询门卫应用程序以确保会话或访问权限令牌仍然有效。后者可能是更好的策略,尽管它最终会产生更多的API调用。

答案 1 :(得分:2)

我认为这篇文章会有所帮助:

A Sane Oauth Federation Strategy With Doorkeeper in Ruby

答案 2 :(得分:2)

我看到它的方式,您可以通过相对复杂的API调用交换(容易出现网络错误,“我的一个应用程序刚刚重启”等)或通过引入来同步应用之间的状态共享存储,最好的选项可能是共享的memcached或共享的redis服务器,它将为您的用户ID存储访问令牌

解决此问题的一种方法是覆盖所有门卫客户端应用的session中的ApplicationController,并在想要获取或设置:access_token时让他们ping共享存储。

请注意,我不是哈希[][]=覆盖的粉丝,因为它违反了principle of least surprise,但我觉得这是这种情况下的最佳方法。

我为您提供了一个示例代码,用于覆盖session的实例来执行此操作:https://gist.github.com/bbozo/f5c28fe9bd804dff0af8使用Dalli memcached client,需要注意的事项:

请注意,我并不是100%确定实例的重写方法没有带有模糊的方法查找回归,因此如果您可以控制session的实例化,那么创建类可能是最安全的继承自HashWithIndifferentAccess的gist中的2个覆盖,然后实例化它而不是默认的哈希类,但除非你期望一些真正严重的流量,否则真的不要为此烦恼。