2009-03-18 10 views
9

Tôi có plugin restful_authentication cài đặt trong một ứng dụng đường ray, với một sessions_controller rằng có một phương pháp phá hủy như thế này:Thoát bằng http basic authentication và plugin restful_authentication

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 

Trong bộ điều khiển ứng dụng tôi có:

before_filter :login_required 

Và Trong sessions_controller tôi có:

skip_before_filter :login_required 

Vấn đề của tôi là khi người dùng xác thực với xác thực cơ bản http, người đó không đăng xuất. phiên bị hủy, nhưng người dùng có thể điều hướng đến các trang bị hạn chế mà không gặp vấn đề gì. Vấn đề này không xảy ra với xác thực phiên thông qua plugin. Làm thế nào tôi có thể làm cho phương pháp này thoát khỏi sự chứng thực cơ bản?

+0

Sessions không RESTful. – deamon

Trả lời

13

Không có gì có thể được thực hiện phía máy chủ để "logout" một người sử dụng trong tình huống này. Khi người dùng đăng nhập thông qua xác thực cơ bản, trình duyệt lưu trữ thông tin xác thực và gửi thông số xác thực thông qua tiêu đề http với mọi yêu cầu. nếu người dùng đăng nhập bằng xác thực cơ bản, họ sẽ phải đóng cửa sổ trình duyệt của mình để đăng xuất.

+1

Đây là một chút hack, nhưng nó đã giải quyết được vấn đề của tôi. Chuyển hướng người dùng đến URL có ID người dùng không hợp lệ được nhúng trong đó. http://stackoverflow.com/questions/5957822/how-to-clear-basic-authentication-details-in-chrome – Snekse

+0

Đề xuất của Snekse từ câu hỏi SO khác cũng phù hợp với tôi. –

1

Rất tiếc, có vẻ như trình duyệt của khách hàng chỉ lưu vào bộ nhớ cache thông tin Xác thực cơ bản HTTP và gửi lại chúng mỗi lần. Trong trường hợp đó bạn không có quyền kiểm soát điều đó. Các hành động mà bạn muốn được bảo vệ cần phải được bảo vệ với before_filter thích hợp cho các plugin restful_authentication, mà nên

require_authentication 

Vì vậy, trong điều khiển của bạn, bạn sẽ phải

before_filter :require_authentication 

HTTP Authentication là quốc tịch - nghĩa là, máy chủ không theo dõi "phiên" đã được xác thực - do đó, máy khách phải cung cấp mỗi lần (vì vậy hộp kiểm thường xuyên 'lưu trữ các thông tin đăng nhập này'), do đó không có cách nào để máy chủ xóa thông tin đăng nhập ứng dụng khách . Đây là một phần của thông số kỹ thuật. Xem các mục Wikipedia

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

Cụ thể, nhìn vào "Nhược điểm" phần.

+0

chỉnh sửa mã để hiển thị các bộ lọc trước tôi có –

1

tôi chỉ cập nhật login_from_basic_auth trong authenticated_sytem đọc:

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

vấn đề với giải pháp này là nó chỉ đơn giản là tắt xác thực cơ bản http, mà không phải là những gì tôi muốn làm. Ngoài ra, nếu bạn muốn tắt auth cơ bản như thế này, bạn nên loại bỏ các cuộc gọi đến phương pháp này bên trong def current_user hơn là viết lại nó. –

4

Tôi đã tìm thấy một cách khá thú vị để khắc phục điều này bằng cách sử dụng biến phiên để nhớ người dùng nào đã đăng xuất. Ý tưởng là mặc dù trình duyệt vẫn gửi dữ liệu xác thực, chúng tôi chỉ bỏ qua nó, bởi vì người dùng đã chọn đăng xuất. Bất cứ khi nào một yêu cầu đăng nhập mới được gửi đến trình duyệt, tất cả dữ liệu xác thực sẽ bị xóa, do đó người dùng có thể đăng nhập lại bất kỳ lúc nào.

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 
     [email protected]_user.nil? 
    end 
    end 

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

Sau đó, trên bộ điều khiển sự kiện mà tôi làm:

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

Và cuối cùng điều khiển phiên của tôi trông như thế này:

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 
     [email protected]_user.nil? 
    end 
    end 

end 

Và đừng quên các tuyến đường của bạn!

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

cảm ơn. bạn thật tuyệt vời – khanh

2

chỉ này hoạt động cho IE 6 SP1 +:

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

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

Lưu ý rằng điều này sẽ xóa bộ nhớ cache cho tất cả các trang web người dùng hiện đang đăng nhập (trong trường hợp IE cùng) .

1

Một cách để sửa lỗi này là để vô hiệu hóa "xác thực http cơ bản" hoàn toàn

Nhưng chúng tôi cần điều này cho trải nghiệm người dùng tốt trong hành động Ajax, vì vậy chúng tôi cho phép xác thực này chỉ dành cho những hành động 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 
1

tôi biết, một chút sau bữa tiệc, nhưng Nếu bạn muốn thoát bạn có thể làm cho 401.

phương pháp để logout có thể trông như thế này:

def logout 
    render :logout, status: 401 
end 

hành động yên tĩnh của bạn có thể trông như thế này:

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 

và trình duyệt sẽ tăng http authentication cơ bản một lần nữa