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

如何将Flask API设为私有仅允许前端调用(代码内实现)

代码内实现Flask API私有访问的方案

以下几种方案都不需要依赖数据库或外部存储,直接在代码内完成权限控制,可根据你的安全需求选择:

1. 检查请求来源(Origin/Referer 头部)

利用浏览器同源策略特性,前端合法请求会携带Origin或Referer头部,直接在代码里定义允许的前端域名,拦截非信任来源的请求。

from flask import Flask, request, abort

app = Flask(__name__)

# 代码内直接配置允许的前端域名(包含本地开发环境)
ALLOWED_ORIGINS = {"https://your-production-frontend.com", "http://localhost:3000"}

@app.before_request
def validate_request_source():
    # 处理CORS预请求(OPTIONS方法)
    if request.method == "OPTIONS":
        response = app.make_default_options_response()
        # 允许信任的域名跨域
        response.headers["Access-Control-Allow-Origin"] = next(iter(ALLOWED_ORIGINS))
        response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
        response.headers["Access-Control-Allow-Headers"] = "Content-Type"
        return response
    
    # 验证Origin头部
    origin = request.headers.get("Origin")
    if origin and origin not in ALLOWED_ORIGINS:
        abort(403, description="Access denied: Invalid origin")
    
    # 可选:补充验证Referer头部作为双重校验
    referer = request.headers.get("Referer")
    if referer and not any(referer.startswith(domain) for domain in ALLOWED_ORIGINS):
        abort(403, description="Access denied: Invalid referer")
    
    return None

# 示例API路由
@app.route("/api/private-data", methods=["GET"])
def get_private_data():
    return {"content": "This data is only for your frontend"}

if __name__ == "__main__":
    app.run()

优缺点:实现简单,无额外依赖;但请求头部可以被伪造,适合对安全性要求中等的内部或非公开场景。

2. 预定义API密钥验证

在代码内固定一个API密钥,前端请求时在请求头中携带该密钥,API端直接校验匹配性。

from flask import Flask, request, abort
import os

app = Flask(__name__)

# 优先从环境变量加载密钥,也可以直接写死在代码中(不推荐硬写,用环境变量更安全)
API_SECRET = os.getenv("API_SECRET_KEY", "your-fixed-secret-12345")

@app.before_request
def validate_api_key():
    # 跳过OPTIONS预请求
    if request.method == "OPTIONS":
        return
    
    # 从请求头获取密钥
    received_key = request.headers.get("X-API-Key")
    if received_key != API_SECRET:
        abort(403, description="Access denied: Invalid API key")
    
    return None

# 受保护的API路由
@app.route("/api/protected", methods=["POST"])
def protected_operation():
    return {"status": "success", "data": "Sensitive information"}

if __name__ == "__main__":
    app.run()

前端调用提示:发送请求时在headers中添加X-API-Key: your-fixed-secret-12345。

优缺点:验证逻辑直观,无需复杂流程;但密钥可能因前端代码被反编译而泄露,建议配合HTTPS使用,且仅用于非公开前端场景。

3. JWT令牌验证(代码内签名/校验)

使用JWT实现无状态验证,密钥直接在代码内配置,无需存储用户信息到数据库。前端先通过固定凭据获取令牌,之后所有请求携带令牌即可。

需要先安装依赖:pip install pyjwt

import jwt
from datetime import datetime, timedelta
from flask import Flask, request, abort, jsonify
import os

app = Flask(__name__)

# 从环境变量加载JWT密钥,或直接定义
JWT_SECRET = os.getenv("JWT_SECRET_KEY", "your-jwt-secret-abc")
TOKEN_EXPIRY_MINUTES = 60  # 令牌有效期60分钟

# 前端获取令牌的接口(用代码内固定的凭据校验)
@app.route("/api/get-token", methods=["POST"])
def get_token():
    # 代码内预定义的前端专属凭据
    valid_frontend_creds = {"client_id": "your-frontend-app", "client_secret": "fixed-secret-xyz"}
    
    request_data = request.get_json()
    if not request_data:
        abort(400, description="Missing request data")
    
    # 校验前端提交的凭据
    if (request_data.get("client_id") != valid_frontend_creds["client_id"] or
        request_data.get("client_secret") != valid_frontend_creds["client_secret"]):
        abort(401, description="Invalid credentials")
    
    # 生成JWT令牌
    payload = {
        "sub": "frontend-client",
        "exp": datetime.utcnow() + timedelta(minutes=TOKEN_EXPIRY_MINUTES)
    }
    token = jwt.encode(payload, JWT_SECRET, algorithm="HS256")
    return jsonify({"access_token": token})

# 全局校验JWT的钩子
@app.before_request
def validate_jwt_token():
    # 跳过令牌获取接口和OPTIONS请求
    if request.path == "/api/get-token" or request.method == "OPTIONS":
        return
    
    auth_header = request.headers.get("Authorization")
    if not auth_header or not auth_header.startswith("Bearer "):
        abort(401, description="Missing or invalid Authorization header")
    
    token = auth_header.split(" ")[1]
    try:
        # 校验令牌有效性
        payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
        # 验证令牌所属的客户端
        if payload.get("sub") != "frontend-client":
            abort(403, description="Not authorized to access this resource")
    except jwt.ExpiredSignatureError:
        abort(401, description="Token has expired")
    except jwt.InvalidTokenError:
        abort(401, description="Invalid token")
    
    return None

# 受保护的API路由
@app.route("/api/secure-data", methods=["GET"])
def get_secure_data():
    return {"data": "This is highly protected data"}

if __name__ == "__main__":
    app.run()

前端调用提示:先调用/api/get-token获取令牌,之后每个请求的Authorization头设置为Bearer <获取到的token>。

优缺点:安全性更高,令牌有有效期,泄露风险更低;实现稍复杂,但无需外部存储,完全在代码内完成控制。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 17:54:50