You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails API使用Devise-JWT无Bearer Token返回问题求助

问题:Rails API中Devise-JWT未返回Bearer Token

我在纯API类型的Rails应用中,尝试使用Devise和Devise-JWT搭建基于Token的身份认证体系,但通过Postman测试API时,响应中并未返回Bearer Token。我对Devise、Token及安全领域相关技术较为陌生,恳请提供相关指导及可行的解决方案。

现有代码

devise.rb

config.jwt do |jwt|
  jwt.secret = ENV['DEVISE_JWT_SECRET_KEY']
  jwt.dispatch_requests = [['POST', /api/]]
  jwt.expiration_time = 12.hours.to_i
end

routes.rb

Rails.application.routes.draw do
  namespace :api do
    devise_for :users, controllers: {
      sessions: 'api/sessions'
    }
  end
end

api/sessions_controller.rb

class Api::SessionsController < Devise::SessionsController
  def create
    user = User.find_by('lower(email) = ?', params[:email])

    if user.blank? || !user.valid_password?(params[:password])
      render json: {
        errors: ['Invalid email/password combination']
      }, status: :unauthorized
      return
    end

    sign_in(:user, user)

    render json: {
      user: user,
      token: user.token
    }
  end
end

user.rb

# frozen_string_literal: true

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable,
         :registerable,
         :recoverable,
         :rememberable,
         :validatable,
         :trackable,
         :jwt_authenticatable,
         jwt_revocation_strategy: JwtDenylist
end

jwt_denylist.rb

class JwtDenylist < ApplicationRecord
  include Devise::JWT::RevocationStrategies::Denylist

  self.table_name = 'jwt_denylist'
end

cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'

    resource '*',
             headers: :any,
             methods: %i[get post put patch delete options head]
  end
end

问题原因分析

  1. 自定义Session控制器覆盖默认逻辑:Devise-JWT原本会自动在匹配请求中返回Token,但你自定义了create方法,且错误调用了不存在的user.token方法——Devise-JWT并未给User模型添加该方法。
  2. dispatch_requests配置范围过宽:当前配置匹配所有POST /api/*请求,虽能覆盖登录接口,但精准度不足;且自定义控制器后,默认的Token响应逻辑已失效。
  3. 未正确获取生成的JWT:调用sign_in后Devise-JWT已生成Token,但你没有通过正确途径获取。

解决方案

1. 修正Session控制器的Token获取逻辑

调用sign_in后,通过request.env['warden-jwt_auth.token']获取生成的Token,并按规范返回Bearer格式:

class Api::SessionsController < Devise::SessionsController
  respond_to :json

  def create
    user = User.find_by('lower(email) = ?', params[:email].downcase)

    if user.blank? || !user.valid_password?(params[:password])
      render json: {
        errors: ['邮箱/密码组合无效']
      }, status: :unauthorized
      return
    end

    sign_in(:user, user)
    jwt_token = request.env['warden-jwt_auth.token']

    render json: {
      user: user.as_json(only: [:id, :email, :created_at]),
      token: "Bearer #{jwt_token}"
    }, status: :ok
  end
end

2. 优化Devise-JWT配置

将dispatch_requests调整为精准匹配登录接口,避免不必要触发:

config.jwt do |jwt|
  jwt.secret = ENV['DEVISE_JWT_SECRET_KEY']
  jwt.dispatch_requests = [['POST', %r{/api/users/sign_in$}]]
  jwt.expiration_time = 12.hours.to_i
end

3. 确保JWT密钥正确配置

在项目根目录的.env文件中添加安全密钥(可通过rails secret生成):

DEVISE_JWT_SECRET_KEY=your_secure_random_secret_here

4. 验证数据库迁移

确保已运行所有必要的迁移:

rails db:migrate

若未生成迁移文件,先执行:

rails generate devise:install
rails generate devise User
rails generate devise_jwt:install
rails db:migrate

测试验证

  1. 启动服务器:rails s
  2. 在Postman中发送POST请求到http://localhost:3000/api/users/sign_in,请求体为JSON格式:
{
  "email": "test@example.com",
  "password": "your_password"
}
  1. 响应中应返回包含Bearer {token}的JSON数据,后续请求可将此Token放入Authorization头进行认证。

内容的提问来源于stack exchange,提问作者scrscr87

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 14:26:00