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

使用googleauth gem在Rails 7 API中验证Google OAuth2访问令牌

解决Rails 7 API验证Google令牌的签名错误问题

首先你混淆了Google的访问令牌(access_token)和ID令牌(id_token):googleauth gem的IDTokens::Verifier专门用于验证ID令牌,而非访问令牌。前端应该传递Google登录返回的id_token,而非access_token。如果必须使用访问令牌,需要调用Google的tokeninfo端点,但更推荐用ID令牌做后端验证。

另外你的代码缺少关键的**受众(Audience)**参数——这是ID令牌验证的必填项,必须严格匹配你在Google Cloud Console中创建的OAuth客户端ID,否则必然触发验证失败。

以下是修正后的验证代码:

def validate_access_token
  # 提取令牌(前端需传递id_token而非access_token)
  token = request.headers['Authorization']&.gsub(/bearer /i, '')
  return render json: { error: 'Missing token' }, status: :unauthorized unless token

  # 替换为你的Google OAuth客户端ID(从Google Cloud Console获取)
  client_id = 'your-google-oauth-client-id.apps.googleusercontent.com'

  # Verifier会自动使用默认的Google证书源,无需手动指定key_source
  verifier = Google::Auth::IDTokens::Verifier.new(audience: client_id)

  begin
    # 验证令牌并返回解码后的用户信息payload
    payload = verifier.verify(token)
    # 可从payload中提取用户唯一标识sub、邮箱等信息,用于关联系统用户
    # current_user = User.find_by(google_id: payload['sub'])
  rescue Google::Auth::IDTokens::VerificationError => e
    case e
    when Google::Auth::IDTokens::ExpiredTokenError
      render json: { error: 'Token expired' }, status: :unauthorized
    when Google::Auth::IDTokens::InvalidAudienceError
      render json: { error: 'Invalid audience' }, status: :unauthorized
    else
      render json: { error: "Token verification failed: #{e.message}" }, status: :unauthorized
    end
  end
end

关键注意事项:

  • 令牌类型:前端需传递Google登录回调中的id_token(比如使用@react-oauth/google库时,response.credential字段就是id_token),不要传access_token。
  • 受众匹配:audience参数必须与Google Cloud Console中创建的OAuth客户端ID完全一致,大小写、字符都不能错。
  • 密钥源:Verifier默认会使用https://www.googleapis.com/oauth2/v3/certs作为证书源,原代码中手动指定这部分是多余且正确的,但无需保留。

若必须验证访问令牌:

如果业务需求只能用access_token,不要用googleauth gem,直接调用Google的tokeninfo端点验证:

def validate_access_token
  access_token = request.headers['Authorization']&.gsub(/bearer /i, '')
  return render json: { error: 'Missing token' }, status: :unauthorized unless access_token

  response = Faraday.get("https://oauth2.googleapis.com/tokeninfo", { access_token: access_token })
  if response.status != 200
    render json: { error: 'Invalid access token' }, status: :unauthorized
  else
    payload = JSON.parse(response.body)
    # 必须验证返回的aud字段是否匹配你的客户端ID
    unless payload['aud'] == 'your-google-oauth-client-id.apps.googleusercontent.com'
      render json: { error: 'Invalid audience' }, status: :unauthorized
    end
  end
end

这种方式需要额外的HTTP请求,验证效率不如ID令牌高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 11:22:25