用户登录Rails时返回JWT令牌

Ben*_*min 6 routes ruby-on-rails devise jwt

使用devise gem和获取JWT令牌时遇到问题devise-jwt gem。这就是我的确认结果。

devise.rb

  Devise.setup do |config|

    config.jwt do |jwt|
      jwt.secret =  SECRETS.devise_jwt_secret_key
      jwt.dispatch_requests = [ ['POST', %r{^/authentication_tokens/create$}] ]
    end
end 
Run Code Online (Sandbox Code Playgroud)

user.rb

class User < ApplicationRecord

    devise :database_authenticatable, :registerable,
           :recoverable, :rememberable, :trackable, :validatable,
           :jwt_authenticatable, jwt_revocation_strategy: Devise::JWT::RevocationStrategies::Null

  end
Run Code Online (Sandbox Code Playgroud)

authentication_tokens_controller.rb

class Api::V1::AuthenticationTokensController < Devise::SessionsController
  include Devise::Controllers::Helpers
  skip_before_action :verify_authenticity_token 

  prepend_before_action :require_no_authentication, only: [:create]

  before_action :rewrite_param_names, only: [:create]

  def new
    render json: { response: "Authentication required" }, status: 401
  end

  def create
    self.resource = warden.authenticate!(auth_options)
    sign_in(resource_name, resource)
    yield resource if block_given?
     render json: {success: true, jwt: current_token, response: "Authentication successful" }
  end

  private

  def rewrite_param_names
    request.params[:user] = {email: request.params[:email], password: request.params[:password]}
  end

  def current_token
    request.env['warden-jwt_auth.token']
  end

end
Run Code Online (Sandbox Code Playgroud)

routes.rb

   get 'home#secret'
   devise_for :users
   resources :tasks
   #other routes for the website removed for brevity

  namespace :api, defaults: { format: :json } do
    namespace :v1 do
      resources :users
      devise_scope :user do
        post '/authentication_tokens/create', to: "authentication_tokens#create"
      end
    end
  end
Run Code Online (Sandbox Code Playgroud)

由于某种原因,始终会request.env['warden-jwt_auth.token']返回null,但是,该用户已通过身份验证。用户登录时,我需要添加什么以获得JWT令牌吗?

更新-路线和命名空间

经过几天的调试,我相信我已经找到了问题的根源。我的应用程序有一个使用常规路由的前端。如果我执行以下代码,则上面的代码将无法正常工作。一切都很好。

  scope :api, defaults: {format: :json} do
    devise_for :users, controllers: {sessions: 'v1/authentication_tokens'}
  end
Run Code Online (Sandbox Code Playgroud)

devise_for即使上面已在网站上使用过,也可以通过一种方式为我命名API吗?

Ale*_*kov 6

你只需要让你的路线RESTful。

路由文件

post '/authentication_tokens', to: "authentication_tokens#create"
Run Code Online (Sandbox Code Playgroud)

设计文件

config.jwt do |jwt|
  jwt.secret =  SECRETS.devise_jwt_secret_key
  jwt.dispatch_requests = [ ['POST', %r{^/authentication_tokens$}] ]
end
Run Code Online (Sandbox Code Playgroud)


小智 5

我简要地查看了您的问题,它可能是错误的,但您可以尝试一下:

查看以下几行

def create
  self.resource = warden.authenticate!(auth_options)
end

def current_token
  request.env['warden-jwt_auth.token']
end
Run Code Online (Sandbox Code Playgroud)

nil如果您说即使从方法返回,用户也正在进行身份验证current_token,那么这意味着 jwt 正确传递,但您获取它的方式是错误的。

尝试调试self.resource = warden.authenticate!(auth_options)行并查看里面包含的内容auth_options,也许您可​​以从那里获取 JWT,或者您只是想走错warden-jwt_auth.token路。也尝试调试这一行,看看您是否应该从request.headers["warden-jwt_auth.token"]或类似的内容中获取“warden-jwt_auth.token”。只需打印出您请求的完整响应并按所需标头进行搜索即可。

我希望这有帮助!