Authenticate user and admin separately - ruby-on-rails

class ApplicationController < ActionController::Base
protect_from_forgery
skip_before_filter :authenticate_user! , :only => ["welcome#index"]
# before_filter :authenticate_user! :except => ["welocme#index"]
def after_sign_in_path_for(user)
# user_dashboard_index_path
user_dashboard_index_path
end
def after_sign_out_path_for(user)
welcome_index_path
end
after_filter :authenticate_admin!
def after_sign_in_path_for(admin)
admin_dashboard_index_path
end
def after_sign_out_path_for(admin)
welcome_index_path
end
end
Admin should not access the users dashboard and similarly user should not access the admin dashboard.
How can I achieve this?

i have done in my project:
protect_from_forgery with: :exception
def after_sign_in_path_for(resource)
if user_signed_in?
user_dashboard_index_path
elsif admin_signed_in?
admin_dashboard_index_path
else
xyz_path
end
end
Same for sign-out:
def after_sign_out_path_for(resource)
if user_signed_in?
welcome_index_path
elsif admin_signed_in?
welcome_index_path
else
xyz_path
end
end
for authentication:
in (welcome/index)
<% if user_signed_in? %>
contant_of user
<% else %>
you are not authenticated #admin can not authenticate this page
<% end %>
Hope it would be helpfull

Related

Pundit keeps asking me to be logged in

I am building a simple website where people can upload their poems and writing new ones.
I am trying to use Pundit so that:
Everyone can see all the poems/poetries (in index)
Only logged in user can create a poetry
Only the user who create the poetry can updated OR delete it
I followed the official following documentations but I still need to login to perform any action in my controller.
I am not sure what I am doing wrong since I am following the docs and it seems a copy/paste type of work.
My code:
poetries_controller.rb
class PoetriesController < ApplicationController
before_action :set_poetry, only: [:show, :edit, :update, :destroy]
def index
#poetries = policy_scope(Poetry).order("RANDOM()").limit(30)
end
def show
end
def new
#poetry = Poetry.new
authorize #poetry
end
def create
Poetry.create(poetry_params)
authorize #poetry
redirect_to poetries_path
end
def edit
end
def update
#poetry.save
redirect_to poetry_path(#poetry)
end
def destroy
#poetry.destroy
redirect_to poetries_path
end
private
def poetry_params
params.require(:poetry).permit(:title, :author, :body)
end
def set_poetry
#poetry = Poetry.find(params[:id])
authorize #poetry
end
end
application_controller.rb
class ApplicationController < ActionController::Base
include Pundit
protect_from_forgery with: :exception
before_action :authenticate_user!
after_action :verify_authorized, :except => :index, unless: :devise_controller?
after_action :verify_policy_scoped, :only => :index, unless: :devise_controller?
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
private
def user_not_authorized
flash[:alert] = "Non sei autorizzato a eseguire questa azione"
redirect_to(root_path)
end
end
poetry_policy.rb
class PoetryPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.all
end
end
def show?
true # Anyone can view a poetry
end
def create?
true # Anyone can create a poetry
end
def update?
record.user == user # Only poetry creator can update it
end
def destroy?
record.user == user # Only poetry creator can update it
end
end
application_policy.rb
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
#user = user
#record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
#user = user
#scope = scope
end
def resolve
scope.all
end
end
end
index.html.erb
<div class="container">
<div class="row">
<% #poetries.each do | poetry| %>
<div class="col-xs-12 col-sm-4">
<% if policy(poetry).show? %>
<%= link_to poetry_path(poetry) do %>
<div class="card">
<div class="card-description">
<h2> <%=poetry.title=%> </h2>
<% a = sanitize(poetry.body.truncate(170), tags: %w(br)) %></p>
<p> <%= a %></p>
<p><i><%=poetry.author=%><i></p>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
<!-- </div> -->
</div>
</div>
You call before_action :authenticate_user! in ApplicationController, that's why Devise doesn't allow you see poetries#index. It's not a Pundit problem at all.
Move this callback from ApplicationController to needed controllers, where you really want to check authentication. And restrict it with particular actions.
class PoetriesController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
end

Can't seem to login

I've been spending a few hours trying to understand sessions and I can't seem to get logged in. I hope someone can tell me what I'm doing wrong.
Application Controller
protect_from_forgery with: :exception
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def authorize
redirect_to '/' unless current_user
end
Session Controller
class SessionsController < ApplicationController
def new
end
def create
#user = User.where(email: params[:email]).first
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = user.id
redirect_to '/'
else
redirect_to '/sessions/new'
end
end
def destroy
session[:user_id] = nil
redirect_to '/'
end
end
User Controller
class UsersController < ApplicationController
before_action :find_user, only: [:show, :edit, :update, :destroy]
def index
#user = User.all
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save!
redirect_to '/'
else
render 'new'
end
end
def show
end
def edit
end
def update
if #user.update
redirect_to '/'
else
render 'edit'
end
end
def destroy
#user.destroy
redirect_to '/'
end
private
def find_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:email, :username, :password, :about_me)
end
end
Sessions/new
<%= form_tag('/sessions', method: "POST") do %>
Email: <%= email_field_tag :email %>
Password: <%= password_field_tag :password %>
<%= submit_tag 'Submit' %>
<% end %>
Routes
root 'users#index'
resources :sessions, only: [:new, :create, :destroy]
resources :users
If there are additional code that would be required please let me know. Also if you know a better convention in order to add login for my user, I'm open to learn different ways. Thank you for everyone help in understanding this problem.

Rails Omniauth twitter gem - not authorizing user correctly

I'm building a Rails app which allows users to create and book onto events. I've integrated the twitter omniauth gem along with devise. It logs me in correctly and redirects back however when I click on the link to create an event or book an event the app redirects me back to the sign in page. I've set the site up so that only signed in users can do this but it doesn't appear to cover the omniauth integration.
I also have no way to sign-out from one user to another if I use Twitter to sign in. I want to add Facebook auth also but want to fix this first. What code (inc. validations) am I missing to cover these functions?
Here's the relevant code so far -
Events Controller -
class EventsController < ApplicationController
before_action :find_event, only: [:show, :edit, :update, :destroy,]
# the before_actions will take care of finding the correct event for us
# this ties in with the private method below
before_action :authenticate_user!, except: [:index, :show]
# this ensures only users who are signed in can alter an event
def index
if params[:category].blank?
#events = Event.all.order("created_at DESC")
else
#category_id = Category.find_by(name: params[:category]).id
#events = Event.where(category_id: #category_id).order("created_at DESC")
end
# The above code = If there's no category found then all the events are listed
# If there is then it will show the EVENTS under each category only
end
def show
end
def new
#event = current_user.events.build
# this now builds out from a user once devise gem is added
# after initially having an argument of Event.new
# this assigns events to users
end
# both update and create actions below use event_params as their argument with an if/else statement
def create
#event = current_user.events.build(event_params)
# as above this now assigns events to users
# rather than Event.new
if #event.save
redirect_to #event, notice: "Congratulations, you have successfully created a new event."
else
render 'new'
end
end
def edit
# edit form
# #edit = Edit.find(params[:id])
#event = current_user.events.find(params[:id])
end
def update
if #event.update(event_params)
redirect_to #event, notice: "Event was successfully updated!"
else
render 'edit'
end
end
def destroy
#event.destroy
redirect_to root_path
end
private
def event_params
params.require(:event).permit(:title, :location, :date, :time, :description, :number_of_spaces, :is_free, :price, :organised_by, :url, :image, :category_id)
# category_id added at the end to ensure this is assigned to each new event created
end
def find_event
#event = Event.find(params[:id])
end
end
Application controller -
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 :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
devise_parameter_sanitizer.for(:account_update) << :name
end
# the application controller
# handles everything across the site
# make the current_user AND the logged_in? available to
# be used in the views as well as the controllers
helper_method :current_user
helper_method :logged_in?
helper_method :logged_out?
def current_user
# this is who I am signed in as
#current_user = User.find(session[:uid])
end
def logged_in?
# am i logged in?
# do i have a cookie called uid?
session[:uid].present?
end
def make_sure_logged_in
# If I'm not logged in, redirect me to the log in page
if not logged_in?
flash[:error] = "You must be signed in to see that page"
redirect_to new_session_path
end
end
def logged_out?
session[:uid] = nil
flash[:success] = "You've logged out"
redirect_to root_path
end
end
index.html.erb - events
<header>
<div class="category">
<%= link_to image_tag('MamaKnows.png'), root_path, id: "home" %>
<% Category.all.each do |category| %>
<li><%= link_to category.name, events_path(category: category.name) %></li>
<% end %>
<!-- The code loop above creates category links to the home page -->
</div>
<nav id="nav">
<% if logged_in? %>
<%= link_to 'Create Event', new_event_path %>
<%= link_to 'Account', user_path(current_user) %>
<%= link_to 'Sign out', destroy_user_session_path, :method => :delete %>
<% else %>
<%= link_to "Create an Event", new_user_session_path %>
<% end %>
</nav>
</header>
<% #events.each do |event| %>
<%= link_to (image_tag event.image.url), event %>
<h2><%= link_to event.title, event %></h2>
<h2><%= link_to event.date.strftime('%A, %d %b %Y'), event %></h2>
<% end %>
OmniauthCallback Controller
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def twitter
#details = request.env["omniauth.auth"]
#provider = #details["provider"]
#provider_id = #details["uid"]
#user = User.where(provider: #provider, provider_id: #provider_id).first
if #user.present?
#sign them in
else
# make a new user
#user = User.new
#user.provider = #provider
#user.provider_id = #provider_id
# because of has_secure_password - will this work?
#user.password = "AAAAAA!!"
#user.password_confirmation = "AAAAAA!!"
# let's save the key and secret
#user.key = #details["credentials"]["token"]
#user.secret = #details["credentials"]["secret"]
# lets fill in their details
#user.name = #details["info"]["name"]
if #provider == "twitter"? #user.save!(:validate => false) : #user.save!
# the above if statement allows for twitter to skip validation which requires an email
#user.email = #details["info"]["email"]
end
#user.save!
end
session[:uid] = #user.id
flash[:success] = "You've signed in"
redirect_to root_path
end
def password_required?
super && provider.blank?
end
end
Any assistance would be appreciated.

Rails DRY problem: Need same code in controller and view

I have the following login check in my page:
class LoungeController < ApplicationController
before_filter :confirm_logged_in
def index
end
end
while confirm_logged_in defined here:
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def confirm_logged_in
return true if current_user
redirect_to(:controller => 'access', :action => 'login')
return false # halts the before_filter
end
def current_user
return false unless session[:user_id]
user = User.find(session[:user_id])
return false unless user
(user.display_name == session[:user_display_name]) ? user : nil
end
end
Now, I want to use confirm_logged_in also in app/views/layouts/application.html.erb:
<% if confirm_logged_in %>
<div id="logged_in_as">You are logged in as <%= session[:user_display_name] %></div>
<div id="logout"><%= link_to("Logout", {:controller => "access", :action => "logout"}, :id => "logout_link") %></div>
<% end %>
How would you suggest to solve this problem ? Where should I define confirm_logged_in ?
You can use helper_method
controller.rb
helper_method :confirm_logged_in, :current_user
protected
def confirm_logged_in
# code...
end
def current_user
# code...
end

Authlogic Current User Question - hiding admin links

I think I am missing something while using the Authlogic gem w/ Rails. To set the stage I have multiple users and each user can create posts and comments. Upon the display of a post or comment I would like to give the user who created them the option to edit or destroy.
I am successfully using the following code to hide and show elements based on if a user is logged in or not but can't seem to find out how to only show these links to the actual user who created them...not any user that is logged in.
<% if current_user %>
<%= link_to 'Edit', edit_question_path(question) %> |
<%= link_to 'Destroy', question, :confirm => 'Are you sure?', :method => :delete %>
<% else %>
<p>nothing to see here</p>
<% end %>
Here is the def of current_user located in the application controller in case I need to change something here.
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details#
helper_method :current_user
private
def current_user_session
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.record
end
end
Authentication solutions like authlogic were not built to support what you're trying to do. There are authorization solutions you can use on top on authlogic that let you do fine-grained checks like whether or not a user may access a given action:
<% if current_user.may_update_question? #question %>
<%= link_to 'Edit', edit_question_path(#question) %>
<% end %>
The example above is uses Aegis.
Try this:
class ApplicationController < ActionController::Base
# add your methods (eg: current_user etc)
helper_method :current_user, :logged_in?, :current_user_is_owner?
def init_data
klass = controller_name.camelize.singularize.constantize #User
param_key = controller_name.camelize.downcase.singularize.to_sym # :user
obj = case (action_name.to_sym)
when :new, :create
klass.new(params[param_key])
when :edit, :show, :destroy
klass.find(params[:id])
when :update
klass.find(params[:id]).tap{|o| o.attributes = params[param_key]}
end
instance_variable_set("##{param_key}", obj) # set the obj to #line_item
end
def require_user
return true if logged_in?
render_error_message("You must be logged in to access this page",
new_user_session_url)
return false
end
def require_owner
obj = instance_variable_get("##{controller_name.singularize.camelize.underscore}") # LineItem becomes #line_item
return true if current_user_is_owner?(obj)
render_error_message("You must be the #{controller_name.singularize.camelize} owner to access this page", root_url)
return false
end
def logged_in?
return current_user != nil
end
def current_user_is_owner?(obj)
logged_in? and obj.respond_to?(:user_id) and
(obj.send(:user_id) == current_user.id)
end
def render_error_message message, url
respond_to do |format|
format.html do
flash[:notice] = message
if request.xhr?
head :bad_request, :error => message
else
redirect_to url
end
end
format.json { render :json => message, :status => :unprocessable_entity }
format.xml { render :xml => message, :status => :unprocessable_entity }
end
end
end
Now in your controller
class PostsController < ApplicationController
before_filter :require_user # all actions require user to be logged in
before_filter :init_data # create a member variable called #post, initialized based on the action
before_filter :require_owner, :only => [:edit, :update, :destroy] #edit, update, and destroy actions require ownership
def update
if #post.save
else
end
end
end
In the view code:
<% if current_user_is_owner?(question) %>
.. display something
<% end %>

Resources