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

Rails纯API项目集成Stripe报错:禁止直接发送信用卡号

Rails纯API集成Stripe信用卡支付报错问题

测试信用卡支付时触发错误:

"Sending credit card numbers directly to the Stripe API is generally unsafe. We suggest you use test tokens that map to the test card you are using, see https://stripe.com/docs/testing."

我清楚不能直接将信用卡信息传给Stripe API,已经尝试先调用Stripe::Token生成令牌,再传入Stripe::Charge方法,但仍报上述错误。

相关代码

用户模型(User)

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :trackable, :validatable
  include DeviseTokenAuth::Concerns::User

  validates :stripe_id, presence: true
  has_many :orders
  before_validation :create_on_stripe, on: :create

  def create_on_stripe
    params = { email: self.email, name: self.first_name }
    response = Stripe::Customer.create(params)
    pry
    self.stripe_id = response.id
  end
end

订单模型(Order)

class Order < ApplicationRecord
  attr_accessor :credit_card_number, :credit_card_exp_month, :credit_card_exp_year, :credit_card_cvv
  belongs_to :user
  has_one :payment
  after_create :create_payment

  enum payment_method: %i[credit_card]
  def create_payment
    params = {
      order_id: id,
      credit_card_number: credit_card_number,
      credit_card_exp_month: credit_card_exp_month,
      credit_card_exp_year: credit_card_exp_year,
      credit_card_cvv: credit_card_cvv
    }
    Payment.create!(params)
  end
end

支付模型(Payment)

class Payment < ApplicationRecord
  attr_accessor :credit_card_number, :credit_card_exp_month, :credit_card_exp_year, :credit_card_cvv
  belongs_to :order
  before_validation :create_on_stripe

  def create_on_stripe
    token = get_token
    params = { amount: order.amount_cents, currency: 'usd', source: token}
    response = Stripe::Charge.create(params)
    self.stripe_id = response.id
  end

  def get_token
    Stripe::Token.create({
      card: {
        number: credit_card_number,
        exp_month: credit_card_exp_month,
        exp_year: credit_card_exp_year,
        cvc: credit_card_cvv,
      }
    })
  end
end

订单控制器(OrdersController)

module Api
  module V1
    class OrdersController < Api::V1::ApiController
      include Pundit
      after_action :verify_authorized, except: [:create]
      def create
        @order = Order.new(order_params.merge(amount_cents: 500, payment_method: 'credit_card'))
        if @order.save
          render json: { order: @order, payment: @order.payment }, status: :created
        else
          render json: @response.errors, status: :unprocessable_entity
        end
      end
      private
      def order_params
        params.require(:data).permit(:user_id, :credit_card_number, :credit_card_exp_month, :credit_card_exp_year, :credit_card_cvv)
      end
    end
  end
end

Postman请求示例

POST http://localhost:3000/api/v1/orders
{
    "data": {
        "user_id": 1,
        "credit_card_number": "4000056655665556",
        "credit_card_exp_month": "12",
        "credit_card_exp_year": "2030",
        "credit_card_cvv": "123"
    }
}

所有参数能正常传递到get_token方法,但在此处触发上述错误。


解决方案

  1. 错误核心原因:Stripe禁止在服务器端直接创建Token(除非持有PCI合规资质),服务器端仅能使用客户端生成的Token或Stripe官方提供的测试Token。

  2. 具体修正步骤:

    • 移除服务器端Stripe::Token.create的逻辑,改为接收客户端生成的Token,或直接使用Stripe测试Token(如tok_visa对应测试卡4242424242424242)。
    • 修改订单控制器参数,接收stripe_token而非信用卡四要素:
      def order_params
        params.require(:data).permit(:user_id, :stripe_token)
      end
      
    • 调整订单模型的create_payment方法,传递stripe_token:
      class Order < ApplicationRecord
        attr_accessor :stripe_token
        # ... 其他原有代码
        def create_payment
          Payment.create!(order_id: id, stripe_token: stripe_token)
        end
      end
      
    • 更新支付模型,直接用传入的Token创建Charge,并关联到已有Stripe客户:
      class Payment < ApplicationRecord
        belongs_to :order
        before_validation :create_on_stripe
        attr_accessor :stripe_token
      
        def create_on_stripe
          params = { 
            amount: order.amount_cents, 
            currency: 'usd', 
            source: stripe_token,
            customer: order.user.stripe_id
          }
          response = Stripe::Charge.create(params)
          self.stripe_id = response.id
        end
      end
      
    • 测试阶段可直接使用Stripe测试Token发起请求:
      {
          "data": {
              "user_id": 1,
              "stripe_token": "tok_visa"
          }
      }
      
  3. 额外建议:

    • 始终将支付方式关联到Stripe客户,便于后续实现订阅、重复支付等功能,符合Stripe设计规范。
    • 确保服务器端使用Stripe测试密钥,避免误操作生产环境。

内容的提问来源于stack exchange,提问作者Rodrigo Ladrón de Guevara

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:27:43