Rails: Warden/Devise - Как захватить URL-адрес перед входом/неудачным доступом
Я пытаюсь выяснить, как перенаправить пользователя на страницу, в которую они вошли (или не вошли в систему), используя Warden/Devise. Я считаю, что есть переменная сеанса где-либо, которая доступна или может быть доступна.
например.
Сценарий 1:
Неавторизованный пользователь переходит на защищенную страницу X;
Перенаправлено на страницу входа;
Пользователь входит в систему;
Пользователь перенаправляется на защищенную страницу x
Сценарий 2:
Неавторизованный пользователь хочет принять защищенное действие на странице x;
Пользователь нажимает ссылку для входа в систему;
Пользователь входит в систему;
Пользователь перенаправляется на страницу x, где действие теперь доступно
Любые указатели оцениваются.
Спасибо!
Ответы
Ответ 1
Существует метод вспомогательного помощника под названием after_sign_in_path_for(resource)
(http://rdoc.info/github/plataformatec/devise/master/Devise/Controllers/Helpers) и переменная сеанса с именем session[:"user.return_to"]
, в которой хранится последняя URL-адрес. Метод after_sign_in_path_for
должен возвращать строку, а затем автоматически разрабатывает этот путь для перенаправления пользователя после входа в систему.
В моем контроллере приложений я добавил следующее, которое перенаправляет моих пользователей на домашнюю страницу, если переменная сеанса не установлена:
def after_sign_in_path_for(resource)
(session[:"user.return_to"].nil?) ? "/" : session[:"user.return_to"].to_s
end
Ответ 2
Вы можете использовать request.referer для получения предыдущего URL.
Ответ 3
Если вы используете CanCan для авторизации, вы можете выполнить это, добавив следующее. Если нет, вы должны иметь возможность адаптировать концепции в свою текущую систему авторизации.
приложение/контроллеры/application_controller.rb
rescue_from CanCan::AccessDenied do |exception|
flash[:error] = exception.message
if user_signed_in?
redirect_to root_url
else
# Adds the protected page to the login url but only if the user is not logged in
redirect_to login_path(:next => request.path)
end
end
def after_sign_in_path_for(resource_or_scope)
# if a protected page found, then override the devise after login path
params[:user]["next"] || super
end
app/views/devise/sessions/new.html.erb
<% if params[:next] %>
<%= f.hidden_field :next, :value => params[:next] %>
<% end %>
Вместо использования переменных сеанса это решение использует параметры в URL для отслеживания защищенной страницы.
Ответ 4
Ничего себе, просто понял, что devise (3.5.2)
делает это сам по себе за кулисами (вокруг действия Devise::SessionsController#new
), никаких дополнительных изменений контроллера не требуется.
Если вам нужно явно store
/get
предыдущий location
, см. мой предыдущий ответ:
В настоящее время (осень 2015 года) существует более сексуальный способ сделать это:
Devise::Controllers::StoreLocation#store_location_for
:
# Stores the provided location to redirect the user after signing in.
# Useful in combination with the `stored_location_for` helper.
store_location_for :user, dashboard_path
redirect_to user_omniauth_authorize_path :facebook
Devise::Controllers::StoreLocation#stored_location_for
:
# Returns and delete (if it navigational format) the url stored in the session for
# the given scope. Useful for giving redirect backs after sign up:
redirect_to stored_location_for(:user) || root_path
Методы обрабатывают связанный с ним session
ключ и значение удаления после прочтения, все, что вам нужно, это предоставить ключ :resource
(:user
в приведенном выше примере) и путь для хранения (dashboard_path
в приведенном выше примере). Подробнее см. источник.
Что касается фактического ответа, это будет примерно так:
class ApplicationController < ActionController::Base
rescue_from CanCan::AccessDenied, with: :access_denied
# ...
private
def access_denied(exception)
store_location_for :user, request.path
redirect_to user_signed_in? ? root_path : new_user_session_path, alert: exception.message
end
def after_sign_in_path_for(resource)
stored_location_for(:user) || root_path
end
end
Ответ 5
вот лучшее, что я мог придумать. Работает отлично также с аутентификацией facebook. добавив дополнительные ограничения на добавление URL-адресов в переменную сеанса, вы можете удалить все больше и больше путей, которые не хотите, чтобы пользователь тоже возвращался (например, обратные вызовы, страницы всплеска, целевые страницы и т.д.)
#ApplicationsController
after_filter :store_location
def store_location
session[:previous_urls] ||= []
# store unique urls only
session[:previous_urls].prepend request.fullpath if session[:previous_urls].first != request.fullpath && request.fullpath != "/user" && request.fullpath != "/user/login" && request.fullpath != "/" && request.fullpath != "/user/logout" && request.fullpath != "/user/join" && request.fullpath != "/user/auth/facebook/callback"
# For Rails < 3.2
# session[:previous_urls].unshift request.fullpath if session[:previous_urls].first != request.fullpath
session[:previous_urls].pop if session[:previous_urls].count > 3
end
def after_sign_in_path_for(resource)
@url = session[:previous_urls].reverse.first
if @url != nil
"http://www.google.com" + @url
else
root_path
end
end