简体   繁体   中英

Devise and Knock gem current_user

I have an application that is using both Devise and Knock. It is using Devise to power the authentication for Active Admin and Knock gem is providing the authentication for my API's

The issue I have is that Knock can't seem to find current_user and I believe this is likely because I am using Devise in the same project.

I have the following setup:

Api Controller

class ApiController < ActionController::API
  include Knock::Authenticable
end

User Controller (for API not ActiveAdmin)

module Api
  module V1
    class UsersController < ApiController      
      before_action :set_user, only: [:show, :update, :destroy]

      # GET /users/1
      def show
        render json: @user
      end

      # POST /users
      def create        
        @user = User.new(user_params)               

        if @user.save
          render json: @user.id, status: :created
        else
          render json: @user.errors, status: :unprocessable_entity
        end
      end

      # PATCH/PUT /users/1
      def update
        if @user.update(user_params)
          render json: @user
        else
          render json: @user.errors, status: :unprocessable_entity
        end
      end

      # DELETE /users/1
      def destroy
        @user.destroy
      end

      private
      # Use callbacks to share common setup or constraints between actions.
      def set_user
        @user = User.find(params[:id])
      end

      # Only allow a trusted parameter "white list" through.
      def user_params
        params.require(:user).permit(:email, :password, :password_confirmation)
      end
    end
  end
end

Auth Controller

module Api
  module V1
    class AuthController < ApiController      
      def auth        
        render json: { status: 200, user: current_user }
      end
    end
  end
end

Current User in this Auth controller returns nothing however in another project I have, without devise, this will correctly return the user.

Is there a way to redefine what current_user is or assign it to something different for the purposes of using Knock?

Try this in your ApplicationController

   # JWT: Knock defines it's own current_user method unless one is already
  # defined. As controller class is cached between requests, this method
  # stays and interferes with a browser-originated requests which rely on
  # Devise's implementation of current_user. As we define the method here,
  # Knock does not reimplement it anymore but we have to do its thing
  # manually.
  def current_user
    if token
      @_current_user ||= begin
        Knock::AuthToken.new(token: token).entity_for(User)
      rescue
        nil
      end
    else
      super
    end
  end

  private

  # JWT: No need to try and load session as there is none in an API request
  def skip_session
    request.session_options[:skip] = true if token
  end

  # JWT: overriding Knock's method to manually trigger Devise's auth.
  # When there is no token we assume the request comes from the browser so
  # has a session (potentially with warden key) attached.
  def authenticate_entity(entity_name)
    if token
      super(entity_name)
    else
      current_user
    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