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

Ruby on Rails集成QuickBooks V3 API:如何保存授权码与Realm ID获取令牌

QuickBooks V3 API对接Rails问题解决方案

1 修正回调地址与路由匹配

你当前无法获取参数的核心原因是授权跳转的回调地址和实际处理回调的控制器动作不匹配,你授权时指定的回调地址是http://localhost:3000/vendors,参数只会传到对应vendors#index动作,你单独写的oauth_callback动作根本没被触发。
首先修改路由配置:

# config/routes.rb
get '/quickbooks/authenticate', to: 'vendors#authenticate'
get '/quickbooks/callback', to: 'vendors#oauth_callback', as: :quickbooks_oauth_callback

然后修改authenticate动作里的回调地址,保持和路由配置完全一致(QuickBooks要求两边地址100%匹配,否则会报错):

def authenticate
  redirect_uri = quickbooks_oauth_callback_url
  # state要存入session用于回调校验,防止CSRF攻击
  state = SecureRandom.hex(12)
  session[:qb_state] = state
  grant_url = $oauth2_client.auth_code.authorize_url(
    redirect_uri: redirect_uri, 
    response_type: "code", 
    state: state, 
    scope: "com.intuit.quickbooks.accounting"
  )
  redirect_to grant_url
end

2 修正oauth_callback动作逻辑

你原有回调动作存在全局变量未正确引用、state未校验、凭证对象未初始化、过期字段未存储的问题,修正后代码如下:

def oauth_callback
  # 校验state是否匹配,防止恶意请求
  if params[:state].present? && params[:state] == session[:qb_state]
    session.delete(:qb_state) # state为一次性凭证,用完清空
    redirect_uri = quickbooks_oauth_callback_url
    # 引用你初始化的全局oauth2客户端
    if resp = $oauth2_client.auth_code.get_token(params[:code], redirect_uri: redirect_uri)
      # 单用户场景直接创建/获取全局凭证,多用户可关联对应用户ID
      quickbooks_credentials = QuickbooksCredential.find_or_create_by(id: 1)
      # 存储所有凭证字段,包括过期时间用于后续自动刷新
      quickbooks_credentials.update!(
        access_token: resp.token,
        access_token_expires_at: Time.at(resp.expires_at),
        refresh_token: resp.refresh_token,
        refresh_token_expires_at: Time.now + 100.days, # QuickBooks刷新令牌默认有效期101天
        realm_id: params[:realmId]
      )
      redirect_to vendors_path, notice: "QuickBooks授权成功"
    end
  else
    redirect_to vendors_path, alert: "QuickBooks授权失败,校验不通过"
  end
end

3 初始化AccessToken代码的放置位置

你提到的这段代码是需要调用QuickBooks接口前,初始化API客户端用的,比如你要拉取QuickBooks里的供应商列表,就可以在vendors#index动作里使用:

def index
  quickbooks_credentials = QuickbooksCredential.first
  # 无凭证时先跳转授权
  unless quickbooks_credentials&.access_token.present?
    redirect_to quickbooks_authenticate_path and return
  end
  # 你提到的初始化代码放在此处
  access_token = OAuth2::AccessToken.new(
    $oauth2_client, 
    quickbooks_credentials.access_token, 
    refresh_token: quickbooks_credentials.refresh_token,
    expires_at: quickbooks_credentials.access_token_expires_at.to_i
  )
  # 自动处理access token过期逻辑
  if access_token.expired?
    new_token = access_token.refresh!
    quickbooks_credentials.update!(
      access_token: new_token.token,
      access_token_expires_at: Time.at(new_token.expires_at),
      refresh_token: new_token.refresh_token || quickbooks_credentials.refresh_token
    )
    access_token = new_token
  end
  # 后续即可正常调用quickbooks-ruby的接口
  service = Quickbooks::Service::Vendor.new
  service.access_token = access_token
  service.realm_id = quickbooks_credentials.realm_id
  @vendors = service.all
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 20:30:02