2009-12-04 21 views
6

Ứng dụng Rails của chúng tôi đang sử dụng Restful Authentication để quản lý người dùng/phiên và có vẻ như việc đăng nhập vào cùng một tài khoản từ nhiều máy tính sẽ giết phiên trên các máy tính khác, do đó sẽ làm mất tính năng "Nhớ thông tin của tôi".Xác thực khôi phục: Cho phép đăng nhập từ nhiều máy tính?

Vì vậy, nói rằng tôi đang ở nhà và đăng nhập vào ứng dụng (và chọn "Nhớ thông tin đăng nhập của tôi"). Sau đó, tôi đi đến văn phòng và đăng nhập (và cũng kiểm tra "Nhớ tôi"). Sau đó, khi tôi trở về nhà, tôi quay lại ứng dụng và phải đăng nhập lại.

Làm cách nào để cho phép đăng nhập từ nhiều máy và giữ chức năng "Nhớ thông tin đăng nhập của tôi" trên tất cả?

Trả lời

9

Bạn sẽ hy sinh một số bảo mật bằng cách thực hiện việc này, nhưng chắc chắn là có thể. Có hai cách bạn có thể thực hiện việc này.

Trước tiên, bạn có thể ghi đè phương thức make_token trong mô hình người dùng của mình. Mô hình hiện được thực hiện như sau.

def make_token 
    secure_digest(Time.now, (1..10).map{ rand.to_s }) 
end 

Mỗi khi người dùng đăng nhập vào, có hoặc không có một cookie, phương pháp make_token được gọi là tạo ra và tiết kiệm rất mới remember_token cho người dùng. Nếu bạn có một số giá trị khác duy nhất cho người dùng không thể đoán được, bạn có thể thay thế phương thức make_token.

def make_token 
    secure_digest(self.some_secret_constant_value) 
end 

Điều này sẽ đảm bảo rằng mã thông báo không bao giờ thay đổi, nhưng cũng sẽ cho phép bất kỳ ai có mã thông báo mạo danh người dùng.

Ngoài điều này, nếu bạn nhìn vào phương pháp handle_remember_cookie! trong tệp authenticated_system.rb, bạn sẽ có thể thay đổi phương pháp này để làm việc cho bạn.

def handle_remember_cookie!(new_cookie_flag) 
    return unless @current_<%= file_name %> 
    case 
    when valid_remember_cookie? then @current_<%= file_name %>.refresh_token # keeping same expiry date 
    when new_cookie_flag  then @current_<%= file_name %>.remember_me 
    else        @current_<%= file_name %>.forget_me 
    end 
    send_remember_cookie! 
end 

Bạn sẽ nhận thấy rằng phương pháp này gọi là ba phương pháp trong mô hình người dùng, refresh_token, remember_me, và forget_me.

def remember_me 
    remember_me_for 2.weeks 
    end 

    def remember_me_for(time) 
    remember_me_until time.from_now.utc 
    end 

    def remember_me_until(time) 
    self.remember_token_expires_at = time 
    self.remember_token   = self.class.make_token 
    save(false) 
    end 

    # 
    # Deletes the server-side record of the authentication token. The 
    # client-side (browser cookie) and server-side (this remember_token) must 
    # always be deleted together. 
    # 
    def forget_me 
    self.remember_token_expires_at = nil 
    self.remember_token   = nil 
    save(false) 
    end 

    # refresh token (keeping same expires_at) if it exists 
    def refresh_token 
    if remember_token? 
     self.remember_token = self.class.make_token 
     save(false)  
    end 
    end 

Cả ba phương pháp này đều đặt lại mã thông báo. forget_me đặt thành nil, trong khi hai thiết bị còn lại đặt giá trị trả về bằng make_token. Bạn có thể ghi đè lên các phương thức này trong mô hình người dùng, để ngăn chúng đặt lại mã thông báo nếu nó tồn tại và không hết hạn. Đó có lẽ là cách tiếp cận tốt nhất, hoặc bạn có thể thêm một số logic bổ sung vào phương thức handle_remember_cookie!, mặc dù điều đó có thể sẽ có nhiều công việc hơn.

Nếu tôi là bạn, tôi sẽ ghi đè remember_me_until, forget_merefresh_token trong mô hình người dùng. Sau đây sẽ làm việc.

def remember_me_until(time) 
    if remember_token? 
    # a token already exists and isn't expired, so don't bother resetting it 
    true 
    else 
    self.remember_token_expires_at = time 
    self.remember_token   = self.class.make_token 
    save(false) 
    end 
end 

# 
# Deletes the server-side record of the authentication token. The 
# client-side (browser cookie) and server-side (this remember_token) must 
# always be deleted together. 
# 
def forget_me 
    # another computer may be using the token, so don't throw it out 
    true 
end 

# refresh token (keeping same expires_at) if it exists 
def refresh_token 
    if remember_token? 
    # don't change the token, so there is nothing to save 
    true  
    end 
end 

Lưu ý rằng bằng cách thực hiện việc này, bạn đang lấy ra các tính năng bảo vệ bạn khỏi bị đánh cắp mã thông báo. Nhưng đó là một quyết định về lợi ích chi phí mà bạn có thể thực hiện.

+0

Cảm ơn một tấn! Vậy chức năng của người dùng đang kiểm tra "Nhớ thông tin đăng nhập của tôi" hoạt động như thế nào? Liệu nó có còn nhớ chúng trong khoảng thời gian được đặt trong phương thức 'remember_me' không? – Shpigford

+0

Nó vẫn ghi nhớ chúng trong 2 tuần, như trong phương thức remember_me, nhưng 2 tuần đó bắt đầu lần đầu tiên mã thông báo được sử dụng. Nói cách khác, nếu bạn đăng nhập từ máy tính A, sau đó 10 ngày đăng nhập từ máy tính B, 4 ngày sau mã thông báo hết hạn trên cả hai máy tính. – jcnnghm

+0

Tuyệt vời. Cảm ơn một lần nữa vì sự giúp đỡ của bạn! – Shpigford

0

Bạn có thể thay đổi những gì remember_token là để đạt được điều này. Bạn có thể thiết lập nó để:

self.remember_token = encrypt("#{email}--extrajunkcharsforencryption") 

thay vì

self.remember_token = encrypt("#{email}--#{remember_token_expires_at}") 

Bây giờ không có gì là máy tính hoặc thời gian cụ thể về dấu hiệu và bạn có thể giữ đăng nhập từ nhiều máy tính.

+0

Hmmm, bạn đang nhắc đến phiên bản nào của Xác thực Restful? Tôi đang sử dụng một phiên bản khá gần đây và 'remember_token' được thiết lập với nhiều phương thức phức tạp và phương thức mã hóa SHA1 phức tạp hơn rất nhiều. – Shpigford

+1

Ah, xin lỗi. Đây là một phiên bản khá cũ mà tôi đã chạy ít nhất một năm. Không nhận ra nó đã thay đổi quá nhiều. – erik

Các vấn đề liên quan