Rails: Warden/Devise - How to capture the url before login/failed access

后端 未结 5 2387
天涯浪人
天涯浪人 2020-12-15 06:50

I am trying to figure out how to redirect a user to the page they logged in from (or failed to login) using Warden/Devise. I figure there is a session variable somewhere tha

相关标签:
5条回答
  • 2020-12-15 07:03

    There is a devise helper method called after_sign_in_path_for(resource) (http://rdoc.info/github/plataformatec/devise/master/Devise/Controllers/Helpers) , and a session variable called session[:"user.return_to"] which stores the last url. The after_sign_in_path_for method needs to return a string, then devise automatically uses this path to redirect the user after login.

    In my application controller I have put the following which redirects my users to the home page if the session variable is not set:

    def after_sign_in_path_for(resource)
        (session[:"user.return_to"].nil?) ? "/" : session[:"user.return_to"].to_s
    end
    
    0 讨论(0)
  • 2020-12-15 07:05

    You can use request.referer to get the previous URL.

    0 讨论(0)
  • 2020-12-15 07:06

    here's the best I could come up with. Works perfectly also with facebook authentication. by adding more restrictions to the prepending of urls to the session variable you can remove more and more paths you don't want the user to return too (e.g. callbacks, splash pages, landing pages, etc)

    #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
    
    0 讨论(0)
  • 2020-12-15 07:13

    Wow, just realized that devise (3.5.2) does this all by itself behind the scenes (around Devise::SessionsController#new action), no additional controller modifications required.

    If you need to explicitly store/get previous location, please see my previous answer:

    Currently (Fall 2015) there's a sexier way to do that:

    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's 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
    

    The methods handle related session key and value deletion after reading, all you need is to provide your :resource key (:user in the example above) and a path to store (dashboard_path in the example above). See source for the details.

    As for the actual answer it'll be something like that:

    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
    
    0 讨论(0)
  • 2020-12-15 07:20

    If your using CanCan for authorization you can accomplish this be adding the following. If not, you should be able to adapt the concepts into your current authorization system.

    app/controllers/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 %>
    

    Instead of using session variables this solution uses params in the URL to keep track of the protected page.

    0 讨论(0)
提交回复
热议问题