2016-03-22 2 views
0

В приложении Rails у меня есть два метода в моем контроллере приложений. Один из них аутентифицирует пользователей (т. Е. Проверяет, зарегистрирован ли пользователь и перенаправляет их для входа в систему, если нет). Другая выполняет первую половину этой задачи (т. Е. Проверяет, вошел ли пользователь в систему).Почему два метода, которые логически идентичны, не выполняют одну и ту же задачу?

Когда проверка завершена, если пользователь вошел в систему, оба этих метода предположительно устанавливают переменную @current_user для пользовательского объекта для пользователя, который в настоящий момент зарегистрирован, используя User.find.

Бывший:

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 
Смежные вопросы