如何用Python+Flask结合Stripe实现付费用户页面访问控制
Got it, let's tackle this step by step. You already have login validation set up, so we just need to add a payment-specific check layer on top. Here's how to ensure only users who paid $10 via Stripe in the last 24 hours can access /basicplan:
1. Update Your User Model to Track Payments
First, you need to store payment details for each user. If you're using SQLAlchemy (common with Flask), add these fields to your User model:
from datetime import datetime from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(db.Model): # Your existing fields (id, email, password_hash, etc.) last_payment_amount = db.Column(db.Integer, default=0) # Stripe uses cents, so 1000 = $10 last_payment_timestamp = db.Column(db.DateTime)
These fields will keep track of how much the user paid last and when the payment went through.
2. Save Payment Data After Successful Stripe Charge
Modify your /plan10 route to update the logged-in user's payment record right after a successful charge. Also, add @login_required here to ensure only authenticated users can initiate payments:
from flask import current_user, request, redirect, url_for import stripe @app.route('/plan10', methods=['POST']) @login_required def plan10(): customer = stripe.Customer.create( email=request.form['stripeEmail'], source=request.form['stripeToken'] ) charge = stripe.Charge.create( customer=customer.id, amount=1000, currency='usd', description='The Product' ) # Update user's payment info in the database current_user.last_payment_amount = charge.amount current_user.last_payment_timestamp = datetime.utcnow() db.session.commit() return redirect(url_for('basicplan'))
Using utcnow() avoids timezone headaches when checking the 24-hour window later.
3. Create a Custom Payment Validation Decorator
Just like @login_required, we'll build a reusable decorator to check if a user meets the payment criteria. Add this to your app code:
from functools import wraps from flask import redirect, url_for, flash from datetime import timedelta def payment_required(min_dollar_amount, time_window_hours=24): def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): # First, make sure the user is logged in if not current_user.is_authenticated: return redirect(url_for('login')) # Check if the user has a valid recent payment min_amount_cents = min_dollar_amount * 100 has_valid_payment = ( current_user.last_payment_amount == min_amount_cents and current_user.last_payment_timestamp is not None and datetime.utcnow() - current_user.last_payment_timestamp <= timedelta(hours=time_window_hours) ) if not has_valid_payment: flash("You need to complete the $10 payment to access this page.", "warning") return redirect(url_for('payment_page')) # Replace with your actual payment page route return f(*args, **kwargs) return decorated_function return decorator
This decorator is flexible—you can adjust the amount and time window for other plans later.
4. Apply the Decorator to Your Restricted Route
Add the @payment_required decorator to your /basicplan route (keep @login_required too for base authentication):
@app.route('/basicplan') @login_required @payment_required(min_dollar_amount=10) def basicplan(): return render_template('basicplan.html')
5. Key Edge Cases to Consider
- Stripe Webhooks: For better reliability, set up Stripe webhooks to update user payment status. If a user closes their browser before the redirect happens, the webhook will still notify your app of a successful charge and update the user's record.
- Expiry Handling: The decorator automatically checks the 24-hour window, so users will be redirected back to payment once their access expires.
- User Feedback: The flash message explains why access is blocked, which improves user experience.
That's all! Now users can't directly access /basicplan without being logged in and having a valid $10 payment from the last 24 hours.
内容的提问来源于stack exchange,提问作者Waleed

