9

我在 rails 应用程序中安装了 restful_authentication 插件,它的 sessions_controller 具有这样的销毁方法:

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

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

before_filter :login_required

在 session_controller 我有:

skip_before_filter :login_required

我的问题是,当用户使用 http 基本身份验证进行身份验证时,他/她没有注销。会话被破坏,但用户可以毫无问题地导航到受限页面。通过插件进行会话身份验证不会出现此问题。我怎样才能使这种方法摆脱基本的身份验证?

4

7 回答 7

13

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

于 2009-04-13T15:41:05.273 回答
4

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

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

然后,在事件控制器上我做:

class EventsController < ApplicationController
  before_filter :authenticate!, :only => [ :new, :create, :edit, :update ]
  #...
end

最后我的会话控制器看起来像这样:

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

并且不要忘记您的路线!

  map.logout 'login', :controller => 'session', :action => 'create'
  map.logout 'logout', :controller => 'session', :action => 'destroy'
于 2009-07-08T21:00:11.397 回答
2

这仅适用于 IE 6 SP1+:

javascript:void(document.execCommand('ClearAuthenticationCache', false)); 

http://msdn.microsoft.com/en-us/library/ms536979(VS.85).aspx

请注意,这将清除用户当前登录的所有站点的缓存(在同一 IE 实例中)。

于 2010-08-06T21:37:33.833 回答
1

嗯,听起来客户端浏览器只是在缓存 HTTP 基本身份验证凭据并每次都重新发送它们。在这种情况下,您无法控制。您希望受到保护的操作需要使用适当的 before_filter 来保护 restful_authentication 插件,这应该是

require_authentication

所以在你的控制器中你会有

before_filter :require_authentication

HTTP 身份验证是无状态的——也就是说,服务器不跟踪经过身份验证的“会话”——因此,客户端必须每次都提供它(因此频繁的复选框“存储这些凭据”),因此服务器没有办法清除客户端凭据。这是规范的一部分。请参阅维基百科条目

http://en.wikipedia.org/wiki/Basic_access_authentication

具体来说,请查看“缺点”部分。

于 2009-03-18T21:29:32.680 回答
1

我刚刚更新了 authenticated_sytem 中的 login_from_basic_auth 以读取:

    def login_from_basic_auth
      false
#      authenticate_with_http_basic do |login, password|
#        self.current_user = User.authenticate(login, password)
#      end
    end
于 2009-04-09T21:27:07.660 回答
1

解决此问题的一种方法是完全禁用“基本 http 身份验证”

但是我们需要在 Ajax 操作期间获得良好的用户体验,因此我们仅对 ajax 操作启用此身份验证

def login_from_basic_auth

  return false unless request.xhr?

   authenticate_with_http_basic do |login, password|
     self.current_user = User.authenticate(login, password)
   end
end
于 2010-08-31T14:55:21.833 回答
1

我知道,派对结束后,但如果你想注销,你可以渲染 401。

所以注销方法可能如下所示:

def logout
  render :logout, status: 401
end

你平静的动作可能看起来像这样:

def destroy
  self.current_user.forget_me if logged_in?
  cookies.delete :auth_token
  reset_session
  redirect_to '/', status: 401, flash: "You have been logged out."
end

并且浏览器将再次提出http基本身份验证

于 2015-06-25T13:16:20.117 回答