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
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'm calling a before_filter to authenticate my API via an auth_token before a user can create a friendship. The problem I have is the before_filter is successfully being called and it is is successfully authenticating the user however after running the before_filter it is not continuing and calling the create method.
Here is what returns when I POST to the create url.
Filter chain halted as :require_auth rendered or redirected
Here is my Friendship Controller create method:
class FriendshipsController < ApplicationController
before_filter :require_auth
def create
friendID = params[:friend_id]
userID = currently_logged_in.id
unless userID == friendID or Friendship.exists?(userID, friendID)
transaction do
create(:user_id => userID, :friend_id => friendID, :status => 'pending')
create(:user_id => friendID, :friend_id => userID, :status => 'requested')
end
end
end
Here is the application controller where the before_filter runs :require_auth
def require_auth
auth_token = request.headers["HTTP_AUTH_TOKEN"]
#user = User.find_by_auth_token(auth_token)
if #user.auth_token
render :status => 200, :json => {:message => "Authorization accepted"}
else
render :status => 401, :json => {:error => "Requires authorization"}
return false
end
end
Any ideas whats going wrong? Thanks.
your require_auth is your problem change it to the following(as you can see in railscasts episode http://railscasts.com/episodes/352-securing-an-api):
def require_auth
authenticate_or_request_with_http_token do |token, options|
user = User.find_by_auth_token(token)
end
end
also move the before_filter into application controller if you need for the whole API if not put require_auth under protected method in ApplicationController and call it with before_filter from FriendshipsController
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.
Having problems figuring this out.
trying to do a
rescue_from NoMethodError, :with => :try_some_options
But its not working.
EDITED:
For testing I'm doing a simple redirect
def try_some_options
redirect_to root_url
end
EDITED 2:
Sample of my controller. Added (exception) as recommended below.
I know the reason I'm getting the error. Using Authlogic and authlogic_facebook_connect plugin. When user is created from the facebook plugin the "MyCar" model, which is associated with a user is not created like it normally is created if a user registers locally. Since I do call on the user model and reference the users car throughout different parts of the site, I would like to do something like what you see below and eventually put it in my application_controller.
class UsersController < ApplicationController
before_filter :login_required, :except => [:new, :create]
rescue_from NoMethodError, :with => :try_some_options
...
def show
store_target_location
#user = current_user
end
def create
#user = User.new(params[:user])
if #user.save
MyCar.create!(:user => #user)
flash[:notice] = "Successfully created profile."
redirect_to profile_path
else
render :action => 'new'
end
end
...
protected
def try_some_options(exception)
if logged_in? && current_user.my_car.blank?
MyCar.create!(:user => current_user)
redirect_to_target_or_default profile_path
end
end
...
end
EDITED 3: Hacked it for now since I know why the error is showing up, but would like to figure out how to rescue_from NoMethodError
class UsersController < ApplicationController
before_filter :login_required, :except => [:new, :create]
before_filter :add_car_if_missing
def add_car_if_missing
if logged_in? && current_user.my_car.blank?
MyCar.create!(:user => current_user)
end
end
end
I just read your post when trying to come up with a solution to the same problem. In the end I did the following:
class ExampleController < ApplicationController
rescue_from Exception, :with => :render_404
...
private
def render_404(exception = nil)
logger.info "Exception, redirecting: #{exception.message}" if exception
render(:action => :index)
end
end
This worked well for me. It is a catch all situation yet it just may help you. All the best.
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