2013-08-28 1 views
2

У меня есть приложение Rails 3.2, для которого требуется вход пользователя (current_user) для доступа к страницам событий, которые являются субдоменами. Я использую программу для аутентификации.Как разрешить незарегистрированным пользователям доступ к странице с ограниченным доступом только один раз?

Есть ли способ разрешить пользователю единовременный доступ к странице событий, если я предоставил прямую ссылку на него? Затем я хотел бы, чтобы у них было предложено войти (или зарегистрироваться), если они попытаются получить доступ к различным страницам событий, или если они уйдут и вернутся в будущем на ту же страницу событий.

Я наблюдал за эпизодом учетной записи гостя на railscasts, но кажется, что пользователь может просто продолжить вход в систему в качестве гостя, не регистрируясь при таком подходе.

Вот мой код события контроллер:

def show 
    @event = Event.find_by_name(request.subdomain) 
    if params[:id].present? 
     @event = Event.find(params[:id]) 
    end 
    # if @event.present? and @event.videos.present? 
     @video = Video.find_by_id(params[:video]) || @event.videos.first 
    # else 
    # @video = @event.videos.first 
    # end 
    # @json = Event.all.to_gmaps4rails 
    if @user = current_user 
    else 
     flash[:alert] = "Please sign in first" 
     redirect_to sign_up_url(:subdomain => false) 
    end 
end 

Спасибо за любую помощь/совет ...

EDIT: Просто чтобы обеспечить более некоторый контекст:

  1. Я буду пытаясь водить много пользователей на эту страницу событий каждую неделю, и я не уверен, что возможно/практично жестко выделить отдельные хэши в URL-адреса, если я просто отправлю одну ссылку через социальные сети и электронную почту и т. д.

  2. Поскольку пользователи нажмут на эту ссылку и перейдут прямо к рассматриваемой странице, никаких действий не будет создано для создания отдельной гостевой модели, поэтому я думаю, что ответ должен быть основан на сеансе, добавив несколько столбцов в существующей модели пользователя, но при условии, что она используется только один раз для каждого пользователя. Я думаю, может быть, ip-адрес будет работать?

+0

Как установить 'current_user'? Вы используете Devise для аутентификации? – zeantsoi

+0

Да, я использую devise для установки current_user – jfdimark

+0

Понял. Пожалуйста, см. Мое предлагаемое решение ниже. – zeantsoi

ответ

2

Наиболее пророческим решение создать переменную сеанса для гостевых пользователей, содержащих логическое значение, указывающее, были ли они или не посетили страницу или нет (и, следовательно, для обеспечения доступа, если они не посещали, и наоборот):

# in your controller 
before_filter :check_guest, :only => :show 

private 

def check_guest 
    # if user isn't logged in 
    if current_user.nil? 
    # if user has already viewed, redirect 
    if session[:viewed] == true 
     flash[:alert] = "Please sign in first" 
     redirect_to sign_up_url(:subdomain => false) 
    # if user hasn't viewed, allow access, but flag as having viewed 
    else 
     session[:viewed] = true 
    end 
    end 
end 

Хотя с помощью сессий является де-факто подход к этому конкретному вопросу, существуют пределы его осуществления:

  • сессия должна оставаться в силе в порядке гостевой доступ отслеживаться
  • конкретного браузера (таким образом, несколько пользователей браузера будут одни и те же сессии)
+0

Спасибо zeantsoi. Этот ответ на основе сеанса кажется, что он будет работать лучше всего для того, что мне нужно. Однако я пробовал это, и он перенаправляет меня на страницу sign_up, я предполагаю, что «session [: seen] = true» автоматически устанавливается и запускается так. Как я могу обновить его как истину только после того, как они на странице? – jfdimark

+0

Попробуйте оценить 'session [: seen] == true' явно. Я обновил свой код, чтобы его отразить. Это заставляет его работать? – zeantsoi

+0

Отлично. Оно работает. Я немного адаптировал его, так что он также сохраняется за пределами сеанса (см. Мой собственный ответ), но это в значительной степени ваше решение, поэтому я принял ваш ответ так же правильно, как и решает мой первоначальный вопрос. – jfdimark

2

One вместо привязки переменных сеанса является привязка одноразового хэша с URL-адресом, например:

http://site.com/event?access_id=AKJHDA23fdsank 

Затем, после посещения события, код доступа удаляется. Это потребует управления кодами доступа в базе данных, но имеет дополнительное преимущество - быть надежным.

Вы могли бы просто создать api url для создания этих ссылок, чтобы упростить процесс совместного использования.

Большинство остальных легко обманывается.

+0

Спасибо Damien. Это звучит как хорошее решение, но на практике я не уверен, что это сработает, поскольку я просто хочу отправить одну ссылку каждую неделю, и я не знаю, как я могу отправить одну ссылку, но она генерирует несколько жестко запрограммированных хэшей. .Если мне известно, если я неправильно понимаю ваш ответ, или если он может быть использован в этом сценарии. – jfdimark

+0

@jfdimark, вы правы, это не соответствует этому конкретному сценарию. Чтобы сделать ваш метод сеанса более надежным, вы можете зарегистрировать свой IP-адрес и другие клиентские данные, которые нелегко изменить. Конечно, с правильным ноу-хау все еще легко обойти. Полагаю, это во многом зависит от того, насколько безопасна эта функциональность. –

0

Я не знаю заранее подготовленного решения для этого, но его не должно быть слишком сложно реализовать. Я хотел бы сделать что-то вроде:

class GuestPass < ActiveRecord::Base 

    belongs_to :event 

    # the guest_passes table has a `code` column that contains a long arbitrary string token 
end 

class Event < ActiveRecord::Base 

    has_many :guest_passes 

    def authenticate_guest_pass!(token) 
    return false unless token 
    guest_passes.where(code: token).first 
    end 

end 

class EventsController < ActiveRecord::Base 

    before_action :load_event, only: [ :show ] 
    before_action :validate_guest_pass, unless: current_user 

    private 

    def load_event 
    @event = Event.find(params[:id]) 
    end 

    def validate_guest_pass 
    pass = @event.authenticate_guest_pass!(params[:pass]) 
    if pass 
     pass.delete 
    else 
     # redirect to sign in or whatever 
    end 
    end 

end 

Тогда вы просто генерировать GuestPass записи и вставить их в ссылках, вы предоставляете: они будут выглядеть /events/1?pass=xyzzy

(код здесь может использовать некоторые белово я не говорю, что это красиво. Но это первый прогон.)

+0

Спасибо, gregates. См. Мое редактирование выше. Поскольку гость будет нажимать ссылку вне приложения, это не вызовет действие, из-за чего невозможно создать отдельную модель guest_pass, поэтому я не уверен, что это решение будет работать. – jfdimark

+0

Мысль заключалась в том, что вы предварительно создавали эти и распространяли URL-адреса, содержащие их. Но я предполагаю, что я вижу, что ваш случай использования немного отличается от того, который я представлял, - вы хотите, чтобы ссылки были повторно использованы, но для любого конкретного пользователя работать только один раз? – gregates

0

Это моя слегка измененная версия решения zeantsoi, с дополнительным преимуществом, которое сохраняется, даже если пользователь уходит из своего сеанса браузера.

def check_guest 
    #if user is logged in 
    unless current_user 
    @event = Event.find_by_name(request.subdomain) 
    #if user has already viewed, redirect 
    if @event.guest_ip_address == request.remote_ip 
     flash[:alert] = "Please sign in first" 
     redirect_to sign_up_url(:subdomain => false) 
    #if user hasn't viewed, allow access, but flag as having viewed and store their ip address in the event model so it knows not to show the page again unless current_user 
    else 
     session[:viewed] = request.remote_ip 
     @event.guest_ip_address = session[:viewed] 
     @event.save! 
    end 
    end 
+0

Это блокирует всех, кроме одного посетителя, за одним и тем же устройством NAT, например, местоположение Starbucks. – Fred

+0

Fred - хорошая точка. Есть ли вариации этого, о которых вы можете думать, что бы достичь того же, но избегать блокировки целого кафе, когда кто-то из этого NAT посетил сайт? – jfdimark

+0

Вы можете сохранить некоторое значение в DOM браузера. Я думаю, что современные браузеры поддерживают DOM-хранилище. – Fred