首页 > 解决方案 > 设计和敲击 gem current_user

问题描述

我有一个同时使用 Devise 和 Knock 的应用程序。它正在使用 Devise 为 Active Admin 提供身份验证,而 Knock gem 正在为我的 API 提供身份验证

我遇到的问题是 Knock 似乎找不到current_user,我相信这很可能是因为我在同一个项目中使用了 Devise。

我有以下设置:

API 控制器

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

用户控制器(用于 API 而非 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

认证控制器

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

Current User在这个 Auth 控制器中没有返回任何东西,但是在我拥有的另一个项目中,没有设计,这将正确返回用户。

有没有办法重新定义 current_user 是什么或将其分配给不同的东西以使用 Knock?

标签: ruby-on-railsrubydevisejwt

解决方案


在你的 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

推荐阅读