class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!, :except => [:index]
before_action :authenticate, :except => [:index]
def authenticate
authenticate_or_request_with_http_basic do |username, password|
basic_auth=User.find_by_email(username)
if basic_auth.valid_password?(password)
sign_in :user, basic_auth
render :json => {:email => current_user.email, :id => current_user.id, :message => "hai ruby"}
else
render plain: "Unauthorized access"
end
end
end
end
I am trying to implement basic authorization in my sample application.When i give correct credentials values as in the user database. It gives json response.when the username and password goes wrong it throws error as "undefined method `valid_password?' for nil:NilClass"
Just change if condition to this:
if basic_auth && basic_auth.valid_password?(password)
This will work because before checking for valid password, you must check whether a user even exists with given email id or not. Otherwise, basic_auth object will be nil and valid_password method on nil object will throw error.
Related
Is there any chance to access authenticate Doorkeeper method from a rails action controller? I would like to skip authentication just for one of my actions('show') but if a specific condition aapplies I want to call the apiauthenticate method to do its job. So in the action 'show', first of all I check a condition, and if does not apply, then I need to activate the api_authenticate. I'm launching a test that should call api_authenticate and stop it there. But for some reason it keeps going on and it does not stop.
This is the code of my controller
skip_before_action :api_authenticate, only: :show
def show
param! :id, String, required: true
post = Services::Posts.find(params[:id])
if post.public
#post = post
#user_id = nil
else
api_authenticate
ap "it shouldnt get here if user is not logged in"
user = current_resource_owner
#post = Services::Posts.show(params[:id], user)
#user_id = user.identity rescue nil
end
end
#more actions....
And this is the api_controller.rb where I have the authenticate method
class ApiController < ApplicationController
protect_from_forgery with: :null_session
# Check the user is authenticated
before_action :api_authenticate
rescue_from ActionController::RoutingError, :with => :route_error
rescue_from ::AbstractController::ActionNotFound, :with => :action_error
rescue_from Exception, :with => :base_error if Rails.env.production?
def api_authenticate
doorkeeper_authorize!()
end
end
I have implemented something similar. Haven't tested the below code, but it should work.
skip_before_filter :doorkeeper_authorize! , only: :show
def show
param! :id, String, required: true
post = Services::Posts.find(params[:id])
if post.public
#post = post
#user_id = nil
else
doorkeeper_authorize!
ap "it shouldnt get here if user is not logged in"
user = current_resource_owner
#post = Services::Posts.show(params[:id], user)
#user_id = user.identity rescue nil
end
end
The Api controller,
class ApiController < ApplicationController
protect_from_forgery with: :null_session
# Check the user is authenticated
before_action :doorkeeper_authorize!
rescue_from ActionController::RoutingError, :with => :route_error
rescue_from ::AbstractController::ActionNotFound, :with => :action_error
rescue_from Exception, :with => :base_error if Rails.env.production?
def doorkeeper_unauthorized_render_options(error: nil)
response_hash = { status: false, description: error.description, expired: false }
response_hash[:expired] = true if error.description == "The access token expired"
{ json: response_hash }
end
end
If the problem persists, please add the params passed to the show action.
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'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.
I'm trying to make it so a Devise user has to be authenticated on the show action of a Rails controller unless show is a certain id. Is that possible? Is there something like the following?
before_action :authenticate_user!, except: [:show id: 1]
skip_before_filter :authenticate_user!, :only => :show, :if => "Provide Condition"
Use the above syntax to skip authentication for specific cases, in your case ids.
So I figured it out.
skip_before_filter :authenticate_user!, :only => :show, :if => lambda {
if params[:id]
#post = Post.find(params[:id])
if #post.id == 1
else
false
end
}