Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the `authenticate_or_request_with_http_token` method

I'm adding some authentication into my Rails API only app like so in my application_controller.rb:

def is_admin
  authenticate_or_request_with_http_token do |token, options|
    if User.find_by(:auth_token => token)
      value = true
    else 
      value = false
    end
  end
end

And in my controller:

admin = is_admin
if admin
  @voices = Voice.all.map do |voice| 
    voice.format
  end
else
  @voices = 'Something else'
end

When I'm logged in, everything works fine as expected, however when I'm not logged in, I get the following error: Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".

While not logged in, I was expecting to get the 'Something else' response, which I'd then go ahead and deal with it accordingly.

Any ideas why is this happening?

like image 286
WagnerMatosUK Avatar asked Jan 24 '16 11:01

WagnerMatosUK


2 Answers

authenticate_or_request_with_http_token is meant to be used in a before_action filter which runs before the action. Or with an explicit return.

If you simply want to check if a user exists you would use authenticate_with_http_token which does not send a response.

# app/helpers/authorization_helper.rb
module AuthorizationHelper
  # returns true/false
  # sets @current_user if the request is authenticated 
  def authenticate!
    return true if @current_user  # avoid re-querying the DB
    authenticate_with_http_token do |token, options|
      @current_user = User.find_by(:auth_token => token)
    end
  end

  def is_admin?
    authenticate!
  end
end

# app/controllers/api_controller.rb
# or whatever controller you use as a base
class ApplicationController < ActionController::API
  include AuthorizationHelper
end

# in your controller
def index
  if is_admin?
    @voices = Voice.all.map do |voice| 
    voice.format
  else
    @voices = 'Something else'
  end
end
like image 115
max Avatar answered Sep 28 '22 06:09

max


You can also do this in addition or rather an option to max's answer.

# app/controllers/application_controller.rb
class ApplicationController
  def authorization!
    authenticate_with_http_token do |token, options|
      @current_user = User.find_by(:auth_token => token)
    end

    unless @user.present?
      # You could return anything you want if the response if it's unauthorized. in this
      # case I'll just return a json object 
      return render json: {
        status: 300,
        message: "Unauthorized access in the API"
      }, status: 401
    end
  end
end

# in your controller just add a before_action method
before_action :authorization

def index
  @voices = Voice.all.map do |voice| 
  voice.format
end

In this case you won't need to add an if statement in every request that requires an authentication.

like image 36
zekromWex Avatar answered Sep 28 '22 05:09

zekromWex