2016-03-22 21 views
0

在Rails應用程序中,我的應用程序控制器中有兩種方法。其中一個用戶對用戶進行身份驗證(即檢查用戶是否已登錄,如果沒有,則將其重定向到登錄)。另一個執行該任務的前半部分(即,檢查用戶是否登錄)。爲什麼邏輯上相同的兩種方法不執行相同的任務?

檢查完成後,如果用戶已登錄,則這兩種方法都假定通過使用User.find爲當前登錄的用戶的用戶對象設置了@current_user變量。

前者:

protected 
def authenticate_user 
    if session[:user_id] 
    # set current user object to @current_user object variable 
    @current_user = User.find session[:user_id] 
    return true 
    else 
    flash[:notice] = "You must log in first." 
    flash[:color] = "invalid" 
    redirect_to(:controller => 'sessions', :action => 'login') 
    return false 
    end 
end 

後者:

def check_login_status 
    if session[:user_id] 
    @current_user = User.find session[:user_id] 
    return true 
    end 
end 

正如你可以看到,對於每個這些方法的前半部分的邏輯是相同的。但是,authenticate_user正確設置了@current_user變量; check_login_status不設置它在所有(如,在佈局文件的檢查報告說@current_user.nil? == true

這是佈局文件的相關部分:

<% if not @current_user.nil? %> 
    Logged in as <%= @current_user.username %> — 
    <a href="/logout">log out</a> — 
    <a href="/dashboard">dashboard</a> — 
    <a href="/contacts">contacts</a> — 
    <a href="/help">help</a> 
    <% if @current_user.is_admin %> 
    — <a href="/admin">admin</a> 
    <% end %> 
<% else %> 
    <a href="/login">log in</a> — 
    <a href="/sign-up">sign up</a> — 
    <a href="/help">help</a> 
<% end %> 

我得到所示的第二組鏈接,這說明我退出。

那麼,爲什麼後者未正確設置@current_user變量?它有什麼用protected標記(雖然我有點懷疑)?

+1

後面的方法實際上被稱爲?也許問題出在路線上,而不是控制器。 –

+0

@ das-g是的,我用'before_filter'調用了它們。 – ArtOfCode

回答

1

我想說最可能的解釋是check_login_status根本沒有被調用,因爲兩者在邏輯上是等價的。但是,兩者都重複相同的認證邏輯!

如果你堅持重新發明授權輪(除非是爲了學習目的),你應該避免將驗證邏輯散佈在你的控制器和視圖中。

相反,您使用助手模塊來創建一個簡單的API進行身份驗證。該模塊應該是知道用戶是如何存儲在會話中的應用程序的唯一部分:

module AuthorizationHelper 
    def current_user 
    return nil unless session[:user_id] 
    # conditional assignment so DB is only queried once! 
    @current_user ||= User.find(session[:user_id]) 
    end 

    def sign_in!(user) 
    reset_session 
    session[:user_id] = user.id 
    @current_user = user 
    end 

    def sign_out!(user) 
    reset_session 
    @current_user = nil 
    end 

    def signed_in? 
    current_user.present? 
    end 
end 

現在我們只包括ApplicationController的幫手。

class ApplicationController 
    include AuthorizationHelper 
    # ... 
end 

我們還希望以可重新使用和可擴展的方式確保授權。做到這一點的一個好方法是提出異常並用rescue_from緩存。

讓我們創建我們自己的錯誤類:

class User < ActiveRecord::Base 
    class AuthorizationError < StandardError; end 
end 

讓我們添加一個授權方法:

module authorizationHelper 
    # .. 
    def authorize! 
    raise User::AuthorizationError unless signed_in? 
    end 
end 

現在我們可以在我們的控制器使用此:

class ThingsController < ApplicationController 
    before_action :authorize! 
end 

但是它不是非常有用,因爲它只是導致應用程序崩潰!讓我們來拯救例外:

class ApplicationController 
    include AuthorizationHelper 
    rescue_from User::AuthorizationError, with: :deny_access 

    def deny_access 
    redirect_to(controller: 'sessions', action: 'login') and return 
    end 
end 
相關問題