Sair com http autenticação básica e plug-in restful_authentication
-
20-08-2019 - |
Pergunta
Eu tenho o restful_authentication plugin instalado em um app Rails, com um sessions_controller que tem um método destruir assim:
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
No controlador aplicativo eu tenho:
before_filter :login_required
E no sessions_controller eu tenho:
skip_before_filter :login_required
O meu problema é que quando um usuário se autentica com http autenticação básica, ele / ela não está desconectado. a sessão é destruída, mas o usuário é capaz de navegar para páginas restritas sem nenhum problema. Este problema não ocorre com autenticação de sessão através do plugin. Como posso fazer este método se livrar do authenication básica?
Solução
Nada pode ser feito do lado do servidor para "logout" um usuário nesta situação. Quando o usuário faz login através de autenticação básica, o navegador armazena as informações de autenticação e envia os parâmetros de autenticação através do http cabeçalhos com cada pedido. Se o usuário fizer login com autenticação básica, ele / ela terá que fechar a janela his / her navegador para sair.
Outras dicas
Eu encontrei uma maneira bastante interessante para superar isso usando uma variável de sessão para lembrar que o usuário se desconectou. A idéia é que mesmo que o navegador ainda está enviando dados de autenticação, estamos apenas ignorá-lo, porque o usuário escolheu para encerrar a sessão. Sempre que uma nova solicitação de login é enviado para o navegador, todos os dados de autenticação é apagado, de modo que o usuário é capaz de fazer login novamente em qualquer altura.
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
Em seguida, sobre os acontecimentos controlador de I fazer:
class EventsController < ApplicationController
before_filter :authenticate!, :only => [ :new, :create, :edit, :update ]
#...
end
E, finalmente, a minha sessão controlador esta aparência:
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
E não esqueça suas rotas!
map.logout 'login', :controller => 'session', :action => 'create'
map.logout 'logout', :controller => 'session', :action => 'destroy'
Isso só funciona para o IE 6 SP1 +:
javascript:void(document.execCommand('ClearAuthenticationCache', false));
http://msdn.microsoft.com/ en-us / library / ms536979 (VS.85) .aspx
Note que isso irá limpar o cache para todos os sites que o usuário está conectado em (dentro da mesma instância IE).
Hmm, parece que o navegador do cliente é apenas o cache as credenciais de autenticação do HTTP Básico e re-enviá-los o tempo todo. Caso em que você não tem controle sobre isso. As ações que você deseja ser protegido necessidade de ser protegida com o before_filter adequada para o plugin restful_authentication, que deve ser
require_authentication
Assim, em seu controlador você teria
before_filter :require_authentication
HTTP Authentication é apátrida - isto é, o servidor não manter o controle de uma "sessão" autenticado - assim, o cliente deve fornecê-lo cada vez que (daí a opção freqüente 'armazenar essas credenciais'), assim não há nenhuma maneira para o servidor para limpar as credenciais do cliente. Esta é parte da especificação. Veja a entrada Wikipedia
http://en.wikipedia.org/wiki/Basic_access_authentication
Especificamente, olhe para a seção "Desvantagens".
Eu login_from_basic_auth em authenticated_sytem acaba de atualizar para ler:
def login_from_basic_auth
false
# authenticate_with_http_basic do |login, password|
# self.current_user = User.authenticate(login, password)
# end
end
Uma maneira de corrigir isso é desativar "básica http autenticação" completamente
Mas precisávamos isso por boa experiência do usuário durante as ações Ajax, por isso habilitado essa autenticação apenas para ações 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
Eu sei, pouco depois da festa, mas se você quer sair você pode processar 401.
Assim o método de logout poderiam esta aparência:
def logout
render :logout, status: 401
end
sua ação repousante poderia esta aparência:
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
eo navegador irá aumentar http básica de autenticação novamente