Logout with http basic authentication and restful_authentication plugin

冷暖自知 提交于 2019-12-18 21:53:46

问题


I have the restful_authentication plugin installed in a rails app, with a sessions_controller that has a destroy method like this:

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

In the application controller I have:

before_filter :login_required

And In the sessions_controller I have:

skip_before_filter :login_required

My problem is that when a user authenticates with http basic authentication, he/she is not logged out. the session is destroyed, but the user is able to navigate to restricted pages with no problem. This problem does not occur with session authentication through the plugin. How can I make this method get rid of the basic authenication?


回答1:


Nothing can be done server-side to "logout" a user in this situation. When the user logs in through basic authentication, the browser stores the authentication information, and sends the authentication parameters through the http headers with every request. if the user logs in with basic auth, he/she will have to close his/her browser window to logout.




回答2:


I've found a quite interesting way to overcome this by using a session variable to remember which user has logged out. The idea is that even though the browser's still sending authentication data, we're just ignoring it, because the user chose to log out. Whenever a new login request is sent to the browser, all the authentication data is erased, so the user is able to log back in any time.

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

Then, on the events controller I do:

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

And finally my session controller looks like this:

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

And don't forget your routes!

  map.logout 'login', :controller => 'session', :action => 'create'
  map.logout 'logout', :controller => 'session', :action => 'destroy'



回答3:


This only works for IE 6 SP1+:

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

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

Note that this will clear the cache for all sites the user is currently logged into (within the same IE instance).




回答4:


Hmm, it sounds like the client browser is just caching the HTTP Basic Auth credentials and re-sending them every time. In which case you have no control over that. The actions that you wish to be protected need to be protected with the proper before_filter for the restful_authentication plugin, which should be

require_authentication

So in your controller you would have

before_filter :require_authentication

HTTP Authentication is stateless - that is, the server does not keep track of an authenticated "session" - thus, the client must supply it each time (hence the frequent checkbox 'store these credentials'), thus there is no way for the server to clear the client credentials. This is part of the spec. See the Wikipedia entry

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

Specifically, look at the "Disadvantages" section.




回答5:


I just updated login_from_basic_auth in authenticated_sytem to read:

    def login_from_basic_auth
      false
#      authenticate_with_http_basic do |login, password|
#        self.current_user = User.authenticate(login, password)
#      end
    end



回答6:


One way to fix this is to disable "basic http authentication" completely

But we needed this for good user experience during Ajax actions, so we enabled this authentication only for ajax actions

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



回答7:


I know, little bit after party, but If you want to logout you can render 401.

so logout method could looks like this:

def logout
  render :logout, status: 401
end

your restful action could looks like this:

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

and browser will raise http basic authentication again



来源:https://stackoverflow.com/questions/660155/logout-with-http-basic-authentication-and-restful-authentication-plugin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!