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

如何在Flask项目中通过Stripe判断用户订阅是否激活?

优化Flask+Stripe订阅状态校验方案

核心思路是将用户订阅状态本地化存储(数据库/缓存),通过Stripe Webhook同步状态变更,页面访问时直接读取本地数据判断,彻底避免每次请求调用Stripe API。以下是具体实现步骤:

1. 本地存储订阅状态

首先在用户模型中添加订阅状态字段,关联Stripe客户ID:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    stripe_customer_id = db.Column(db.String(100), unique=True)
    subscription_status = db.Column(db.String(20), default="inactive")
    # 其他用户字段...

2. 配置Stripe Webhook同步状态

监听Stripe订阅相关事件,实时更新本地用户的订阅状态,同时必须验证Stripe签名确保请求合法:

import stripe
from flask import request, jsonify

# 替换为你的Stripe Webhook密钥
STRIPE_WEBHOOK_SECRET = "your_webhook_secret"

@app.route('/stripe-webhook', methods=['POST'])
def stripe_webhook():
    payload = request.get_data(as_text=True)
    sig_header = request.headers.get('Stripe-Signature')

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, STRIPE_WEBHOOK_SECRET
        )
    except ValueError:
        # 无效payload
        return jsonify(success=False), 400
    except stripe.error.SignatureVerificationError:
        # 无效签名
        return jsonify(success=False), 400

    # 处理核心订阅事件
    if event['type'] in ['customer.subscription.created', 'customer.subscription.updated', 'customer.subscription.deleted']:
        subscription = event['data']['object']
        customer_id = subscription['customer']
        
        # 更新本地用户状态
        user = User.query.filter_by(stripe_customer_id=customer_id).first()
        if user:
            user.subscription_status = subscription['status']
            db.session.commit()

    return jsonify(success=True), 200

需要在Stripe后台将该Webhook地址(如https://your-domain.com/stripe-webhook)配置为监听上述三个订阅事件。

3. 改造订阅状态校验逻辑

替换原有的check_subs函数,优先读取本地数据库状态,仅在必要时兜底调用Stripe API:

def check_subs(user_id):
    user = User.query.get(user_id)
    if not user:
        return 0
    
    # 首次访问或本地状态异常时,同步一次Stripe数据
    if user.subscription_status == "inactive":
        subs = stripe.Subscription.list(customer=user.stripe_customer_id)
        if subs['data']:
            latest_status = subs['data'][0]['status']
            user.subscription_status = latest_status
            db.session.commit()
            return 1 if latest_status == 'active' else 0
        return 0
    
    return 1 if user.subscription_status == 'active' else 0

4. 更新页面路由

路由逻辑无需大幅改动,直接复用改造后的校验函数即可:

@app.route('/home')
def home_page():
    if check_subs(session['user_id']) == 0:  # 确保session['user_id']对应用户模型的主键ID
         flash("用户订阅已过期")
         return redirect(url_for('payment_page'))
    return render_template('home.html')

@app.route('/dashboard')
def dashboard_page():
    if check_subs(session['user_id']) == 0:
         flash("用户订阅已过期")
         return redirect(url_for('payment_page'))
    return render_template('dashboard.html')

额外优化建议

  • 高并发场景下,可将订阅状态存入Redis等缓存,进一步提升读取速度,Webhook更新时同步更新缓存与数据库。
  • 每日执行一次全量用户订阅状态同步,避免Webhook漏接事件导致的状态不一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 10:06:22