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

Rails API控制器无法获取已解码JWT Token问题求助

问题:Rails API中JWT解码成功但控制器无法获取内容

我开发了一个用JWT实现登录的Rails API,登录流程正常,Token已存入本地存储,但在通过Token解码做控制器动作授权时遇到问题。多个控制器用authorize_request作为前置动作,定义在ApplicationController中:

class ApplicationController < ActionController::API
  def not_found
    render json: { error: 'not_found' }
  end

  def authorize_request
    header = request.headers['Authorization']
    header = header.split(' ').last if header
    puts "header is #{header}"
    begin
      @decoded = JsonWebToken.decode(header)
      puts "decoded header is #{@decoded}"
      @current_user = User.find(@decoded[:user_id])
      puts "current_user is #{@current_user}"
    rescue ActiveRecord::RecordNotFound => e
      render json: { errors: e.message }, status: :unauthorized
    rescue JWT::DecodeError => e
      render json: { errors: e.message }, status: :unauthorized
    end
  end
end

JsonWebToken类的decode方法代码:

class JsonWebToken
  SECRET_KEY = Rails.application.secrets.secret_key_base

  def self.encode(payload, exp = 24.hours.from_now)
    payload[:exp] = exp.to_i
    JWT.encode(payload, SECRET_KEY)
  end

  def self.decode(token)
    puts("decoding token: #{token}")
    decoded = JWT.decode(token, SECRET_KEY)
    puts("decoded is #{decoded}")
    HashWithIndifferentAccess.new decoded
  end
end

日志显示Token在JWT类中解码成功,但控制器里@decoded是空的:

header is eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjZiZmQyMDAtZDExMy00NjdlLTkwMmEtMDRjMmI5YjE2ZmUwIiwiZXhwIjoxNjgwNzAyMzExfQ.x95ikz4QeWAdgm2rak_L6eUOqhILsRIepvALGieAwx8
decoding token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNjZiZmQyMDAtZDExMy00NjdlLTkwMmEtMDRjMmI5YjE2ZmUwIiwiZXhwIjoxNjgwNzAyMzExfQ.x95ikz4QeWAdgm2rak_L6eUOqhILsRIepvALGieAwx8
decoded is [{"user_id"=>"66bfd200-d113-467e-902a-04c2b9b16fe0", "exp"=>1680702311}, {"alg"=>"HS256"}]
decoded header is {}
原因分析

从日志能看到,JWT.decode返回的是一个数组,第一个元素是包含用户信息的payload,第二个是JWT的头部信息。但你在JsonWebToken.decode方法里,直接把整个数组传给了HashWithIndifferentAccess.new,这会把数组的索引(0、1)作为键,对应的值是数组元素,但你需要的是payload部分,也就是数组的第一个元素。当你在控制器里访问@decoded[:user_id]时,这个键不存在,所以获取不到值,打印出来的@decoded看起来是空的(实际是包含索引键的Hash,但你没用到)。

解决方案

修改JsonWebToken的decode方法,只取数组的第一个元素(payload)来转成HashWithIndifferentAccess:

class JsonWebToken
  SECRET_KEY = Rails.application.secrets.secret_key_base

  def self.encode(payload, exp = 24.hours.from_now)
    payload[:exp] = exp.to_i
    JWT.encode(payload, SECRET_KEY)
  end

  def self.decode(token)
    puts("decoding token: #{token}")
    decoded = JWT.decode(token, SECRET_KEY)
    puts("decoded is #{decoded}")
    # 取数组第一个元素(payload)转成HashWithIndifferentAccess
    HashWithIndifferentAccess.new decoded[0]
  end
end

这样修改后,@decoded就会包含user_id和exp字段,控制器里就能正常通过@decoded[:user_id]找到对应的用户了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 01:55:36