Protect routes from users who are not signed in - ruby-on-rails

I'm using Rails 4 and Devise to authenticate users. Once a user logs in, they are redirected to a sinatra app. I need the route to that page to be protected from unsigned-in users.
So the route I need to prevent users from visiting if they are not signed in is /kibana
Here is my routes files:
devise_for :user
root 'pages#home'
mount Kibana::Sinatra::Web => '/kibana', :trailing_slash => true
Any help is much appreciated, thank you.
EDIT here is my ApplicationController file
protect_from_forgery
before_filter :check_user
private
def check_user
if request.fullpath =~ /kibana/ && !user_signed_in?
authenticate :user do
end
end
end
Yet, not the result I need. When I visit localhost:3000 it redirects me to the user login with the note that I need to be logged in, but when I visit /kibana/ it just shows it without having to be logged in.

More or less this way:
class ApplicationController
before_filter :check_user
private
def check_user
if !current_user && request.fullpath =~ /kibana/
redirect_to your_app_login_url
end
end
end
Edit:
It looks like I was wrong, within your routes.rb:
authenticate :user do
mount Kibana::Sinatra::Web => '/kibana', :trailing_slash => true
end

Related

Ruby on Rails: redirect unauthenticated user to root instead of the sign in page

I am using Rails 4 and Devise 3.
I am using the following in the routes file to prevent access to a page from non authenticated users (not signed in):
authenticate :user do
#page to protect
end
This redirects me to the user/sign_in page, but I want the user to be redirected to the root. So, I added the following as well to the routes page:
get 'user/sign_in' => redirect('/')
But this will mess up what I did in the sessions_controllers:
def new
return render :json => {:success => false, :type => "signinn", :errors => ["You have to confirm your email address before continuing."]}
end
This will stop showing. So, I would like another solution that redirects users to the root directly, instead of having to use authenticate :user and then get 'user/sign_in' => redirect('/').
The following may not have anything to do with redirecting the user to the root, but I would like to explain more about why I am overwriting the new method in the sessions_controller. I moved the sign_in and sign_up views to the root page (home page). In this case, I also needed to hack the error messages so that they appear in the home page, instead of redirecting the user to user/sign_in to show the errors. I used ajax for that.
Update
What I am looking for is something like this:
if user_authenticated?
#show the protected page
else
# redirect the user to the ROOT
end
You can set your devise scope to look something like this.
devise_scope :user do
authenticated :user do
root :to => 'pages#dashboard', as: :authenticated_root
end
unauthenticated :user do
root :to => 'session#new', as: :unauthenticated_root
end
end
EDIT (Based on the new info):
If you have something like this in your routes.rb
root to: 'visitors#index`
then you can have something like this in your visitors_controller.rb
class VisitorsController < ApplicationController
def index
if current_user
redirect_to some_authenticated_path
else
# business logic here
end
end
end
You will still want to handle the propper authorization requirements and authentication requirements in the some_authenticated_path controller and action.
I'm sorry I didn't understand your question, anyway you can do something like this:
class CustomFailure < Devise::FailureApp
def route(scope)
#return super unless [:worker, :employer, :user].include?(scope) #make it specific to a scope
new_user_session_url(:subdomain => 'secure')
end
# You need to override respond to eliminate recall
def respond
if http_auth?
http_auth
else
redirect
end
end
end
And in config/initializers/devise.rb:
config.warden do |manager|
manager.failure_app = CustomFailure
end
This was taken from the wiki of devise:
https://github.com/plataformatec/devise/wiki/How-To%3a-Redirect-to-a-specific-page-when-the-user-can-not-be-authenticated

Redirect to log in page if user is not authenticated with Devise

I'm using Devise with Ruby on Rails.
What is the recommended way to redirect unauthenticated users to the sessions#new page if they attempt to access a page that requires authentication?
Right now I get an error that says no route matches the one they attempt to access (leading to a 404 error in production).
Just simple add this method to application_controller.rb
protected
def authenticate_user!
if user_signed_in?
super
else
redirect_to login_path, :notice => 'if you want to add a notice'
## if you want render 404 page
## render :file => File.join(Rails.root, 'public/404'), :formats => [:html], :status => 404, :layout => false
end
end
And you can call this method on before_filter another controllers you want.
e.g :
class HomesController < ApplicationController
before_filter :authenticate_user!
## if you want spesific action for require authentication
## before_filter :authenticate_user!, :only => [:action1, :action2]
end
Don't forget add login_path into routes.rb
devise_scope :user do
match '/sign-in' => "devise/sessions#new", :as => :login
end
note : I always use this way when play with devise for my apps authentication.. (rails 3.2 and rails 4.0.1)
You can do just like GeekTol wrote, or just put
before_action :authenticate_user!
in your controller.
In this case, devise uses the default authenticate_user! method, that will redirect to the "user_session_path" and use the default flash message.
It's not necessary to rewrite authenticate_user! method, unless you want to customize it.
I thought you could just add:
before_action :authenticate_user!
to each controller that required the user to be logged in.
I'm a Rails beginner but I found this in my own searches and it works well in my application.
You should refer to Devise's own How To: How To: Redirect to a specific page when the user can not be authenticated.
Another alternative I can think of is creating a routing Constraint wrapping your protected routes. You'd better stick to Devise's way, but here is an example:
#On your routes.rb
constraints(Constraints::LoginRequired) do
get '/example'
end
#Somewhere like lib/constraints/login_required.rb
module Constraints
class LoginRequired
def self.matches?(request)
#some devise code that checks if the user is logged in
end
end
end
Add this code in your config/routes.rb devise_for :users and resources :users and you can generate devise in views.

before_filter require_login creates an infinite loop

I'm new to ruby and Rails. I'm Using Devise and CanCan along with Rails_Admin in my app.
I'm trying to do -> If a user is already logged in, and it's an admin, redirect to rails_admin_path if it's not an admin but just a user then redirect to 'upload_path', if it's not logged in then redirect to sign_in path, however probably due to my lack of knoledge, I'm creating an infinite redirect loop. Even if I try to access sign_in without the "require_login" filter.
Here's what I've done so far:
application_controller.rb
class ApplicationController < ActionController::Base
before_filter :require_login
protect_from_forgery
#IDEA 1
#def require_login
# if current_user.role? == 'Administrator'
# redirect_to rails_admin_path
# elsif current_user.role? == (('C1' or 'D1') or ('M1' or 'M2'))
# redirect_to upload_path
# end
# end
#I saw this somewhere and It doesn't work either
def require_login
redirect_to new_user_session_path, alert: "You must be logged in to perform this action" if current_user.nil?
end
rescue_from CanCan::AccessDenied do |e|
redirect_to new_user_session_path, alert: e.message
end
end
routes.rb
Siteconfigurationlistgenerator::Application.routes.draw do
mount RailsAdmin::Engine => '/admin', :as => 'rails_admin'
devise_for :users
# The priority is based upon order of creation:
# first created -> highest priority.
match 'upload' => 'upload_file#new'
.
.
.
ability.rb
class Ability
include CanCan::Ability
def initialize(user)
#Define abilities for the passed in user here.
user ||= User.new #guest user (not logged in)
#a signed-in user can do everything
if user.role == 'Administrator'
#an admin can do everything
can :manage, :all
can :access, :rails_admin # grant access to rails_admin
can :dashboard # grant access to the dashboard
elsif user.role == (('C1' or 'M1') or ('D1' or 'M1'))
# can :manage, [ProductList, Inventory]
# can :read, SiteConfigurationList
# end
end
end
When I run rake routes, I get the routes for Devise and the Rails_admin routes, plus the "upload" route.
I've really tried to fix this stupid error but honestly I ran out of ideas. I'd appreciate any help you're able to provide me. Thank you in advance.
The problem is that you have a before_filter that requires a user to sign in, in your ApplicationController. Basically you are asking your users to sign in before accessing the sign in page.
You can solve this by using devise's built-in method :authenticate_user :
before_filter :authenticate_user!
Or you can specify that your before_filter doesn't run on an action from the DeviseController.
before_filter :require_login, :unless => :devise_controller?

Devise: Sign Up Page as Welcome/Landing Page then to User Profile

Using devise, how do i make my Sign Up as my landing/welcome page and then after sign up they go inside the site to the Profile/signed in area?
I am trying to figure out how to make it like where Facebook their is two sides of the website; the Outside (sign up, about,contact,etc) and The Inside (Profile,sign out,etc) for Users only after sign up or sign in.
Thank you.
P.S. I am new at Ruby on Rails and creating applications but i did do the authentication system with the Rails 3 Tutorial, i understand most things to start using Devise, i jst dont know where to start with this situation.
I was going to use 2 application layouts, 1 before sign up which is layouts/welcome.html.erb with PagesController (about,terms,etc) and the other for signed in users which will be layouts/application.html.erb with ApplicationController (profile,news,add,etc), is this the best steps?
in your routes.rb:
root :to => 'welcome#index'
Where welcome is the controller and index is the action.
In your application controller:
def after_sign_in_path_for(user)
"/url_you_want_to_redirect_to/"
end
This my new and updated way using Rails 3.1.0 and Devise 1.5.0:
routes.rb
root :to => "pages#redirect_to_sign_up"
devise_for :users do
get "welcome" => "devise/registrations#new", :as => :new_user_registration
get "account_settings" => "devise/registrations#edit"
get "sign_in" => "devise/sessions#new"
get "sign_out" => "devise/sessions#destroy"
get "new_password", :to => "devise/passwords#new"
end
match 'home', :to => "user_pages#home"
namespace :user do
root :to => "user_pages#home"
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def after_sign_in_path_for(resource)
stored_location_for(:user) || root_path
end
private
def after_sign_out_path_for(resource)
stored_location_for(:user) || root_path
end
end
pages_controller.rb
class PagesController < ApplicationController
def redirect_to_sign_up
if signed_in?.blank?
redirect_to new_user_registration_path
else
redirect_to home_path
end
end
end
user_pages_controller.rb
class UserPagesController < ApplicationController
before_filter :authenticate_user!
def home
end
def profile
end
end
I find it easiest to root to the desired authenticated landing page and just use a before_filter to force the user to sign in/sign up first via a before_filter.
In this case, let's say your "signed in area" is a controller/action called profile/index.
In your routes.rb, set the root to profile/index.
root :to => 'profile#index'
Then in your profile_controller, set the following before_filter.
before_filter :authenticate_user!
This will automatically push a logged in user (or one that logged in earlier and set a Remember Me cookie) straight to the profile page. Any unauthenticated users will automatically end up on Sign In. You'll want a link (or separate tab) on that page to Sign Up as well.
On the root page check to see if the user is signed in, and redirect based on that.
redirect_to sign_up_path if current_user.nil?
Alternatively, you could render different templates instead of a redirect, but I think it's cleaner to have a 1:1 mapping between urls and pages.
Another approach is to modify devise. Edit devise_gem_path/lib/devise/failure_app.rb and replace the two occurrences in the redirect_url method of:
:"new_#{scope}_session_path"
with:
:"new_#{scope}_registration_path"
A less destructive solution would make redirect_url's response more configurable.

Routing root to display user's posts for logged in users and static page for non-logged in

Story: A non logged in user should see a welcome static page and when he's logged in he should see a list of his blog posts.
I suppose the right way to do this is to route root to the action that lists all the user's posts which then checks for authentication. If the user isn't logged in then it renders the welcome page?
I need help with writing an action for the posts controller which displays posts for the logged in user.
routes.rb:
root :to => "posts#index"
post_controller.rb
class PostsController < ApplicationController
before_filter :authenticate_user!
def index
#posts = current_user.posts.all
end
end
If the user is not logged in, the before filter catches this and redirects somewhere (login? error message?). Otherwise the index method is called and the index view rendered.
This would work out of the box with devise, if you roll another authentication you need to adapt and/or write your own helpers, e.g. something like this:
application.html.erb
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_user
helper_method :user_signed_in?
private
def current_user
#current_user ||= User.find_by_id(session[:user_id]) if session[:user_id]
end
def user_signed_in?
return 1 if current_user
end
def authenticate_user!
if !current_user
flash[:error] = 'You need to sign in before accessing this page!'
redirect_to signin_services_path
end
end
end
I had this problem but didn't want a redirect (adds delay and changes url) so I'm deciding between constraints suggested in User-centric Routing in Rails 3 or scoped routes mentioned in Use lambdas for Rails 3 Route Constraints
Constraints
root :to => "landing#home", :constraints => SignedInConstraint.new(false)
Scoped routes
scope :constraints => lambda{|req| !req.session[:user_id].blank? } do
# all signed in routes
end

Resources