I'm using Devise + ominauth2 to allow users to sign in via different services. If they sign in they get a slightly better experience but if not life still goes on. However I don't see a way with Devise to have a page that allows both authenticated and unauthenticated access.
For example:
class SomeController < ApplicationController
before_action :authenticate_user!
def some_action
end
end
In the above controller, some_action is only accessible if the user authenticates. But what I actually want is something more like:
class SomeController < ApplicationController
def some_action
loadSessionFromCookieIfExists
end
end
Then, I can use user_signed_in? in my views. But this doesn't work because authenticate_user! will redirect them elsewhere. Unless there is an authenticate_if_possible method?
So what I have now, which is really gross is:
class SomeController < ApplicationController
before_action :authenticate_user!
skip_before_action :authenticate_user!, :only=>[:no_auth]
def action
do_stuff
return
end
def no_auth
do_stuff
return
end
private
def do_stuff
render :template => "action"
end
end
I should add, that omniauth2 doesn't support rememberable out of the gate so it's possible this is all supposed to work just fine and the problem is with omniauth2.
Related
I want one pages of my ruby on rails web application inaccessible to one of my STI model types. I have two models typeA and typeB inheriting from User. I have used the column type in the User table to implement STI. I am using Devise gem for User sessions. I want one webpage 'http://localhost:3000/rate' inaccessible to my typeA User. Whenever an User logs in who is of the type 'typeA', he does not have the option of seeing the link 'Rate'. But I also do not want him to be able to access that page by the link 'http://localhost:3000/rate'. If he tries to access it through that link, I want to sign him out and make him log in again.
I managed this by using a piece of code in my Controller with the specific method for 'rate'.
def rate
if current_user.type == "typeA"
sign_out(current_user)
redirect_to new_user_session_path
else
#Code for User of typeB
end
end
This is working but I wanted to know if this can be done in a better way using before_filter :authenticate_user! or something else
Right now my before_filter part looks like this
before_filter :authenticate_user!, except: [:index, :show]
Is there any way I can make a change to the upper code to achieve that functionality.
P.S: Maybe this can be done better if I had used roles or other gems like CanCan/Pundit but I do not have much time left to submit my project, so I do not want to get into all that right now.
you can add another before_filter on the controller you want to restrict the access just to confirm your STI user type without overiding devise's authenticate_user! filter.
application_controller.rb
class ApplicationController < ActionController::Base
def confirm_user_type(user_type)
redirect_to new_user_session_path unless current_user.is_a?(user_type)
end
end
pages_controller.rb
class PagesController < ApplicationController
# must be authenticated to access
before_filter :authenticate_user!
# must be user of TypeA to access
before_filter { |c| c.confirm_user_type(TypeA) }
def rate
...
end
end
Then, you can use the same filter before_filter { |c| c.confirm_user_type(TypeB) } for STI user type: 'TypeB'
Try this:
class ApplicationController
before_action :authenticate_user!
def authorize_user!
if current_user.type == "typeA"
sign_out(current_user)
redirect_to new_user_session_path
end
end
end
with your controller:
class SomeController < ApplicationController
before_action :authorize_user!, except: [:index, :show]
def top_secret
...
end
end
I believe if a before_action (the new name for before_filter) renders or redirects, the action won't be processed.
I'm using the CanCan gem in my Rails app and want to check if the current request is a protected resource in my application.
So for example I have the following:
class AdminController < ApplicationController
load_and_authorize_resource
end
How can I check if the request is protected by CanCan?
I can access the controller and action via params. I can't use the standard can? and cannot? helpers as they will check if the current_user has permission rather than if the action itself has a protection on it.
So for example:
class ApplicationController < ActionController::Base
before_action :check_protected
def check_protected
if can? params[:action].to_sym, Object.const_get(params[:controller].classify)
# resource is protected
else
# resource is not protected
end
end
end
^^ This won't work because it will always say false when no current_user or if the user doesn't have permission. I need to check if the resource itself is protected with CanCan.
If I had these examples:
class PostsController < AdminController
def index
end
end
class HomeController < ApplicationController
def index
end
end
The index for PostsController should be identifiable as protected, and the index for HomeController as unprotected.
CanCan uses CanCan::ControllerResource#skip? method to determine whether it should authorize resource or not. So I guess you may rely on it as follows:
def check_protected
if CanCan::ControllerResource.new(self).skip?(:authorize)
# resource is not protected
else
# resource is protected
end
end
I've tried it in my sandbox and it worked for me
I have this view called Intranet where only authenticated "devise clients" can access.
class IntranetController < ApplicationController
before_action :authenticate_client!
def index
end
end
On the other side, I also have other "devise admin", this devise admin requires to access the same view. How can I handle this situation?
Try this:
class IntranetController < ApplicationController
before_action :authenticate_all!
def index
end
def authenticate_all!
if admin_signed_in?
true
else
authenticate_client!
end
end
end
I am setting up a very simple rails app that involves a simple authentication check before you can enter the site. But, when the before_filter runs, and the user is redirected to the login path, a redirect loop occurs.
ApplicationController:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :check_session
private
def check_session
redirect_to login_path and return unless current_user?
end
def current_user?
!session[:username].blank?
end
end
SessionsController
class SessionsController < ApplicationController
def new
end
end
The issue is that, since your SessionsController inherits from ApplicationController, it actually inherits the before_filter as well. This means you are not allowing someone to see the login page unless they are logged in, which is usually undesirable behavior. You want to skip this before_filter on the login page:
class SessionsController < ApplicationController
skip_before_filter :check_session, only: :new
def new
end
end
I think you have problem in your routes. One way of solution is defining a root path for your app as:
root 'app_entry#index'
Then create a controller for it as given below:
class AppEntryController < ApplicationController
def index
if current_user
redirect_to 'controller_name/action_name'
else
redirect_to '/users/sign_in'
end
end
Hope this helps you.
You should use the before filter like this
before_filter :check_session, :except => [:new]
Currently, my ApplicationController looks like this:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
include CurrentUser
protect_from_forgery with: :exception
before_action :authorize
before_action :get_current_user
protected
def authorize
unless User.find_by(id: session[:user_id])
redirect_to login_url, notice: "Please log in"
end
end
end
As you can see, authorize checks to make sure a user is login, and if not - redirects them to the login page. This works perfectly.
On the "front facing" pages, where users don't have to be logged in, I do this:
skip_before_action :authorize, only: [:names, :of, :ok, :pages]
Now, I have added some pages where elevated privileges are required, so that method would (I think) look something like this:
def check_for_elevated_role
u = User.find(id: session[:user_id])
unless u.role >= 10
redirect_to some_url, notice: "Insufficient Role"
end
end
My question is, what is the best way to implement this? Should I simply add this as a before action to the pages I want to lock down, or (Like I did with authorize), add this to the ApplicationController and skip this on pages where users don't need privileges (that's the safe way, right?). Whatever the case, can you show me what the before_actions should look like?
I'm adding this as an answer as it's a little long as a comment.
You most probably want to create a different controller with that before_action and inherit from that controller
class AuthorizeController < ApplicationController
before_action :authorize_admin
protected
def authorize_admin
# your logic here
end
end
class ControllerThatNeedsAuthorizationController < AuthorizeController
skip_before_action :action_that_doesnt_need_authorization
end