使用http基本身份验证和restful_authentication插件注销

Chr*_*ier 9 authentication ruby-on-rails ruby-on-rails-plugins

我在rails应用程序中安装了restful_authentication插件,其session_controller具有如下所示的destroy方法:

def destroy
  self.current_user.forget_me if logged_in?
  cookies.delete :auth_token
  reset_session
  flash[:notice] = "You have been logged out."
  redirect_back_or_default('/')
end
Run Code Online (Sandbox Code Playgroud)

在应用程序控制器中我有:

before_filter :login_required
Run Code Online (Sandbox Code Playgroud)

在sessions_controller我有:

skip_before_filter :login_required
Run Code Online (Sandbox Code Playgroud)

我的问题是,当用户使用http基本身份验证进行身份验证时,他/她不会注销.会话被销毁,但用户可以毫无问题地导航到受限制的页面.通过插件进行会话身份验证不会发生此问题.如何使这种方法摆脱基本的认证?

Chr*_*ier 13

服务器端无法在这种情况下"注销"用户.当用户通过基本身份验证登录时,浏览器会存储身份验证信息,并在每次请求时通过http标头发送身份验证参数.如果用户使用基本身份验证登录,他/她将必须关闭他/她的浏览器窗口才能注销.


Mih*_*san 5

我发现了一种非常有趣的方法来克服这个问题,即使用会话变量来记住哪个用户已注销。这个想法是,即使浏览器仍在发送身份验证数据,我们也只是忽略它,因为用户选择了注销。每当新的登录请求发送到浏览器时,所有身份验证数据都会被删除,因此用户可以随时重新登录。

class ApplicationController < ActionController::Base
  # ...

  before_filter :authenticate

  protected

  def authenticate
    authenticate_with_http_basic do |username, password|
      @current_user = User.find_by_name_and_crypted_password(username, User.digest(password))
      @current_user = nil if @current_user && session[:logged_out] == @current_user.id
      !@current_user.nil?
    end
  end

  def authenticate!
    return if @current_user
    session[:authenticate_uri] = request.request_uri
    redirect_to('/login')
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,在事件控制器上我执行以下操作:

class EventsController < ApplicationController
  before_filter :authenticate!, :only => [ :new, :create, :edit, :update ]
  #...
end
Run Code Online (Sandbox Code Playgroud)

最后我的会话控制器如下所示:

class SessionController < ApplicationController
  before_filter :authenticate!, :only => [ :create ]

  def create
    if session[:authenticate_uri]
      redirect_to(session[:authenticate_uri])
      session[:authenticate_uri] = nil
    else
      redirect_to(new_event_path)
    end
  end

  def destroy
    session[:logged_out] = @current_user.id
    redirect_to '/'
  end

  protected

  def authenticate!
    authenticate_or_request_with_http_basic("Rankings") do |username, password|
      @current_user = User.find_by_name_and_crypted_password(username, User.digest(password))
      if @current_user && session[:logged_out] == @current_user.id
        @current_user = nil
        session[:logged_out] = nil
      end
      !@current_user.nil?
    end
  end

end
Run Code Online (Sandbox Code Playgroud)

并且不要忘记您的路线!

  map.logout 'login', :controller => 'session', :action => 'create'
  map.logout 'logout', :controller => 'session', :action => 'destroy'
Run Code Online (Sandbox Code Playgroud)