I would like to check whether the request is XML od HTML. When HTML the page is redirected to login form (if a user is not logged in) and when XML the user get not authorized status code.
Example:
class ApplicationController < ActionController::Base
def require_user
unless current_user
IF XML
RESPOND WITH CODE
ELSE
redirect_to :controller => :user_sessions, :action => :new, :format => params[:format]
END
return false
end
end
end
class ProductsController < ApplicationController
before_filter :require_user
...
end
You should be able to use the format delegation method:
unless (current_user)
respond_to do |format|
format.xml do
# respond with code
end
format.html do
redirect_to :controller => :user_sessions, :action => :new, :format => params[:format]
end
end
return false
end
Related
I am trying to create an action that checks if a user is permitted to perform a certain action and if the user isn't then I want to redirect the user to an "Access Denied" view
This is how my current setup is
class PermissionController < ApplicationController
def authorize(permission_id)
is_permitted = is_user_permitted(permission_id)
respond_to do |format|
format.js { render :json => {:is_permitted => is_permitted, :redirect => url_for(:controller => 'welcome', :action => 'index' , notice: "No access")}}
format.all { redirect_to :controller => 'welcome', :action => 'index' , notice: "No access" unless is_permitted == true }
end
end
end
I want to call the authorize action in the :before_filter of another controller.
How do I do that?
I can't put the authorize action in the ApplicationController since I want to define a route to this action in routes.rb
#NickM has covered this in his comment... have OtherController inherit from PermissionController
class PermissionController < ApplicationController
def authorize
...
end
end
class OtherController < PermissionController
before_filter :authorize
end
However I note your authorize method has a parameter?
You'll need to handle that in the before_filter clause. Assuming you can store permission_id in a session variable...
class PermissionController < ApplicationController
def authorize(permission_id)
...
end
end
class OtherController < PermissionController
before_filter { |controller| controller.authorize(session[:permission_id] }
end
Why don't you try something like this, assuming you have the user's id stored in session:
class ApplicationController < ActionController::Base
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
def authorize
# If user is NOT permitted
if !is_user_permitted(current_user)
# Response for you ajax here
respond_to do |format|
format.js { render :json => {:is_permitted => false, :redirect => url_for(:controller => 'welcome', :action => 'index' , notice: "No access")}}
format.all { redirect_to :controller => 'welcome', :action => 'index' , notice: "No access" }
end
end
end
end
class SomeOtherChildController < ApplicationController
before_filter :authorize, :only => [:show, :new, :edit]
# or you can use :except => [:index, :create, :destroy, :update] instead of :only.
# No authorization required
def index
end
# Authorization required
def show
end
# Authorization required
def new
end
# No authorization required
def create
end
# Authorization required (Ajax response for your "Edit" button)
def edit
# authorize method in ApplicationController will be called first
# If user is authorized, then the rest of this action will be executed
respond_to do |format|
format.js { render :json => {:is_permitted => true} }
end
end
# No authorization required
def update
end
# No authorization required
def destroy
end
end
Take this as an outline and general concept to what you might want to implement.
This is typically a concept I implement with permissions in my apps. You probably wouldn't want to put the Permissions logic in a separate child class controller, because in order to check permissions, you would either have to create a reference object of the PermissionsController (that is ugly and very un-Rails like) and use it within whatever controller you're trying to check permissions for, or you will have all other controller classes inherit from the PermissionsController, which isn't terrible, but certainly not ideal.
If users can have multiple types of permissions, you are probably better off creating a Permission model and controller, with a User has_many Permissions relationship, where the logic in the authorize method would become a bit easier to implement.
I am building an API in Rails and using Devise for Authentication. My front-end is an AngularJS app. I am able to log in and create a new session on the Rails end, but as soon as I try to access the current_user method in my UsersController it's nil. Am I missing something here?
Appreciate any help. Thanks
SessionsController:
class SessionsController < Devise::SessionsController
respond_to :json
def create
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
render :status => 200,
:json => { :success => true,
:info => "Logged in",
:user => current_user
}
end......
UsersController:
class UsersController < ApplicationController
before_filter :authenticate_user!, :except => [:create, :show]
respond_to :json
def show
render :json => {:info => "Current User", :user => current_user}, :status => 200
end....
I had to define current_user and run a custom authentication filter in my API to get the information straight from warden. I got the information below from a conglomeration of a few places here and here and a lot of trial and error with a debugger.
before_filter :api_session_authenticate!
private
def current_user
warden.user
end
def warden
env['warden']
end
def api_session_authenticate!
return not_authorized unless authenticate
end
def authenticate
warden.athenticated?
end
def not_authenicated
#render error messages and 401 status
end
I have a custom method outside the generic CRUD in my friendships controller called request. My problem is that I have before_filter :require_auth set to run before all methods in my FriendshipsController.
It was working fine except for the request method.
(This makes me think it has something to do with it being out of normal CRUD?)
When I call the request method now it skips the :require_auth and goes straight to the request method which is giving me errors as I define some variables in :require_auth that I need inside the request method.
Here is my FriendshipsController:
class FriendshipsController < ApplicationController
skip_before_filter :verify_authenticity_token, :only => [:create]
before_filter :require_auth
def create
#friendship = Friendship.new(user_id: params[:user_id], friend_id: params[:friend_id], status: params[:status])
if #friendship.save
render :status => 200, :json => {:message => "Friendship Created"}
else
render :status => 500, :json => { :message => "Problem creating friendship" }
end
end
def request
# friendID = params[:friend_id]
# userID = #currentuser.id
binding.pry
#userid = #currentuser.id
#friendid = params[:friend_id]
unless (#userid == #friendid || Friendship.exists?(user_id: #userid,friend_id: #friendid))
create(:user_id => userID, :friend_id => friendID, :status => 'pending')
create(:user_id => friendID, :friend_id => userID, :status => 'requested')
end
end
end
Here is my ApplicationController where I define require_auth:
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: :null_session
def require_auth
binding.pry
auth_token = request.headers["HTTP_AUTH_TOKEN"]
#user = User.find_by_auth_token(auth_token)
if #user.auth_token
#currentuser = #user
else
render :status => 401, :json => {:error => "Requires authorization"}
return false
end
end
end
Chris Peters was right in the comments. My problem was that rails already has request defined. I simple changed the method name to something else and it works.
Thanks.
I have an issues with connecting loose end in oauth and authlogic.
I'm running rails 3.0.9 with authlogic working fine and I wanted to add on twitter login.
The issue that I'm having is that after logging in on twitter instead being redirected to call back url defined in twitter dev settings. The app redirects to top domain while appending this to the url
user_sessions?oauth_token=[t_o_k_e_n]
I don't have index action in user_sessions_controller.rb, so I get the action index couldn't be found error, but I can't decipher why I'm being redirected to this url?
My user_sessions.rb
class UserSession < Authlogic::Session::Base
# def to_key
# new_record? ? nil : [ self.send(self.class.primary_key) ]
# end
#
# def persisted?
# false
# end
#
def self.oauth_consumer
OAuth::Consumer.new("asdasdsad", "asdasdasdas",
{ :site=>"http://twitter.com",
:authorize_url => "http://twitter.com/oauth/authenticate"})
end
end
My user_sessions_controller.rb
class UserSessionsController < ApplicationController
# GET /user_sessions/new
# GET /user_sessions/new.xml
def new
#user_session = UserSession.new
end
# POST /user_sessions
# POST /user_sessions.xml
def create
#user_session = UserSession.new(params[:user_session])
#user_session.save do |result|
if result
flash[:notice] = "Login successful!"
redirect_back_or_default root_path
else
render :action => :new
end
end
# respond_to do |format|
# if #user_session.save
# format.html { redirect_to(root_path, :notice => 'User session was successfully created.') }
# format.xml { render :xml => #user_session, :status => :created, :location => #user_session }
# else
# format.html { render :action => "new" }
# format.xml { render :xml => #user_session.errors, :status => :unprocessable_entity }
# end
# end
end
# DELETE /user_sessions/1
# DELETE /user_sessions/1.xml
def destroy
#user_session = UserSession.find
#user_session.destroy
respond_to do |format|
format.html { redirect_to(root_path, :notice => 'Goodbye!') }
format.xml { head :ok }
end
end
end
I even tried adding
:oauth_callback => "http://127.0.0.1:3000/"
to the Consumer.new clause, but that didn't help.
Lastly, my routes.rb looks like this:
resources :users, :user_sessions
match 'login' => 'user_sessions#new', :as => :login
match 'logout' => 'user_sessions#destroy', :as => :logout
Anyone has any ideas on how to troubleshoot this or had a similar problem?
https://dev.twitter.com/sites/default/files/images_documentation/oauth_diagram.png defines quite clearly what you should send and get from Twitters Oauth Provider.
Are you sure you get a oauth_callback_confirmed in step B, if so you might wanna contact Twitter why they validate your oauth_callback then modify it
I'm trying to use sweepers to handle my page refreshes. For refreshing index actions, etc everything works fine...but I can't seem to sweepers to interpret page parameters. If anyone can tell me what's wrong with the code below, I'd be very appreciative:
Controller:
class PostsController < ApplicationController
load_and_authorize_resource
cache_sweeper :post_sweeper, :only => [:create, :update, :destroy]
caches_page :index
caches_page :show
caches_action :edit, :new
# This refreshes cache correctly
def index
#posts = Post.all
end
# This creates cache, but does not refresh it (ever). If I place the expire_page command directly into the action (instead of the sweeper), it works fine
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = t(:post_updated)
format.html { redirect_to(#post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
The sweeper:
class PostSweeper < ActionController::Caching::Sweeper
observe Post
def after_create(record)
expire_cache_for_index(record)
end
def after_update(record)
expire_cache_for_index(record)
expire_cache_for_post(record)
expire_cache_for_edit(record)
end
def after_destroy(record)
expire_cache_for_index(record)
expire_cache_for_post(record)
expire_cache_for_edit(record)
end
private
def expire_cache_for_index(record)
expire_page :controller => 'posts', :action => 'index'
end
def expire_cache_for_post(record)
expire_page :controller => 'posts', :action => 'show', :id => record.id
end
def expire_case_for_edit(record)
expire_action :controller => 'posts', :action => 'edit', :id => record.id
end
end
If we assume you copy and pasted the code, then the typo is also in your code. Since you did not get flagged with an error by Rails, we can then assume that the sweepers are not being called. (i.e. the after_update is not being called). I would add some logger messages in to verify that that really is the case.
Questions is about Post:
Is it a decedent of ActiveRecord::Base?
Do you have other callbacks that are returning false and thus stopping the chain?
The sweeper examples on the net consistently put the cache_sweeper line after the caches_xxx lines. I'd be surprised if that makes a difference but its worth checking out.