Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby On Rails Devise Mobile Api

I'm building mobile api based on Devise.

As long as I need json responses I have implemented custom SessionController and RegistrationController:

my routes.rb looks like:

devise_for(:users, :controllers => { :sessions => "api/sessions", :registrations => "api/registration"})

AFAIK, since last update auth_token in Devise is not used anymore (CHANGELOG.md under 3.1.0.rc).

Here is my registration controller:

class Api::RegistrationController < Devise::RegistrationsController
  respond_to :json
  skip_before_filter :verify_authenticity_token

  def create
    user = User.new(params[:user])
    if user.save
      render :json=> {:auth_token=>user.authentication_token, :email=>user.email}, :status=>201
      #render :json=> {:success=>true}, :status=>201
      return
    else
      warden.custom_failure!
      render :json=> user.errors, :status=>422
    end
  end


  protected

  def invalid_login_attempt
    render :json=> {:success=>false, :message=>"Error with your login or password"}, :status=>401
  end
end

and session controller:

class Api::SessionsController < Devise::SessionsController
  prepend_before_filter :require_no_authentication, :only => [:create ]
  before_filter :ensure_params_exist

  respond_to :json
  skip_before_filter :verify_authenticity_token

  def create
    resource = User.find_for_database_authentication(:email => params[:email])
    return invalid_login_attempt unless resource

    if resource.valid_password?(params[:password])
      sign_in("user", resource)
      resource.ensure_authentication_token
      render :json=> {:success=>true, :auth_token=>resource.authentication_token, :email=>resource.email}
      return
    end
    invalid_login_attempt
  end

  def destroy
    sign_out(resource_name)
  end

  protected
  def ensure_params_exist
    return unless params[:email].blank?
    render :json=>{:success=>false, :message=>"missing user_login parameter"}, :status=>422
  end

  def invalid_login_attempt
    warden.custom_failure!
    render :json=> {:success=>false, :message=>"Error with your login or password"}, :status=>401
  end
end

My user model:

class User < ActiveRecord::Base
  before_save :ensure_authentication_token
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  attr_accessible :email, :password, :password_confirmation, :remember_me


  def ensure_authentication_token
    if authentication_token.blank?
      self.authentication_token = generate_authentication_token
    end
  end

  private
  def generate_authentication_token
    loop do
      token = Devise.friendly_token
      break token unless User.where(authentication_token: token).first
    end
  end
end

As you can see from above, I've used this question to generate my own auth token. Unfortunately, after I authenticate with following query

curl -X POST -d '[email protected]&password=password' http://192.168.178.89:3000/users/sign_in

I obtain a token. But when I try to get protected data:

curl -X GET -d 'auth_token:UR-Hespxerzorw9UPK9Z' http://192.168.178.89:3000/api/orders.json

I get:

{"error":"You need to sign in or sign up before continuing."}

Can anyone point me to correct way of authentication? Thanks!

like image 208
user2786037 Avatar asked Jan 07 '14 21:01

user2786037


1 Answers

To do so, you can do the following steps:

1- Remove the before_filter :authenticate_user! from the superclass of OrdersController class, which should be ApplicationController.

2- Create your own token check by adding the followings to your OrdersController class:

before_filter :restrict_access

# Methods not shown

protected

def restrict_access
   authenticate_or_request_with_http_token do |token, options|
      User.exists?(authentication_token: token)
   end
end

This looks for the authentication_token you had created in the User model and will match it with the request's token parameter.

3- To test the API, you can use the following curl command:

curl -X GET -H 'Authorization: Token token="sdfksdf34heg5Ms"' http://192.168.178.89:3000/api/orders.json

where the token is what you got in response of the sign in request.

like image 98
NRR Avatar answered Oct 24 '22 12:10

NRR