简体   繁体   中英

Rails 5 Devise: Return JSON On sign_in Failure

Everything I seem to find on this issue is out of date and/or doesn't work.

GOAL: When a user tries to sign in via JSON from a mobile application and the username or password is wrong, I would like Rails to return JSON data so the errors can be displayed on the app.

So far I have done the following:

class Users::SessionsController < Devise::SessionsController
  # before_action :configure_sign_in_params, only: [:create]
  skip_before_action :verify_authenticity_token
  respond_to :json

  # POST /resource/sign_in
  def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message(:notice, :signed_in) if is_flashing_format?
    sign_in(resource_name, resource)
    yield resource if block_given?
    respond_with resource, :location => after_sign_in_path_for(resource) do |format|
      format.json {render :json => resource } # this code will get executed for json request
    end
  end
end

This works well on success, but I'm not sure what to do when it fails. Right now it returns an undefined method error:

undefined method `users_url' for #<Users::SessionsController:0x0000000195fa28>

You should take a look at this SO question that will point you in the right direction.

Basically you need to handle the login failure. You could do this:

class CustomFailure < Devise::FailureApp
  def respond
    if http_auth?
      http_auth
    elsif request.content_type == "application/json"
      self.status = 401
      self.content_type = "application/json"
      self.response_body = {success: false, error: "Unauthorized"}.to_json
    else
      redirect
    end
  end
end

This handles JSON requests. I hope this helps!

Figured it out. CustomFailure never seemed to work, no matter how many things I tried. I was able to do this within the SessionsController via handle_failed_login:

class Users::SessionsController < Devise::SessionsController
  # before_action :configure_sign_in_params, only: [:create]
  after_filter :handle_failed_login, :only => :new
  skip_before_action :verify_authenticity_token
  respond_to :json

  # POST /resource/sign_in
  def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message(:notice, :signed_in) if is_flashing_format?
    sign_in(resource_name, resource)
    yield resource if block_given?
    respond_with resource, :location => after_sign_in_path_for(resource) do |format|
      format.json {render :json => resource } # this code will get executed for json request
    end
  end

  private
  def handle_failed_login
    if failed_login?
      render json: { success: false, errors: ["Login Credentials Failed"] }, status: 401
    end
  end 

  def failed_login?
    (options = env["warden.options"]) && options[:action] == "unauthenticated"
  end 
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM