基于来源有条件支持credentials是否可行?Flask API相关CORS疑问
针对特定来源条件开启CORS凭证支持的Flask实现方案
方案合理性
你的需求完全合理,这是典型的跨域权限控制场景——为可信来源开放携带Cookie/HTTP认证信息的权限,限制非可信来源仅能发起无凭证请求,既满足多来源调用需求,又能保障接口安全。
实现方式
方式一:基于Flask-CORS扩展实现动态配置
Flask-CORS支持通过函数动态返回CORS配置,刚好可以用来实现按来源条件开启凭证支持:
- 先安装依赖:
pip install flask-cors
- 示例代码:
from flask import Flask, request from flask_cors import CORS app = Flask(__name__) # 配置你的可信来源列表 TRUSTED_ORIGINS = ["https://trusted-domain1.com", "https://trusted-domain2.com"] def dynamic_cors_config(): origin = request.headers.get('Origin') if origin in TRUSTED_ORIGINS: # 可信来源:允许具体Origin,开启凭证支持 return { 'origins': origin, 'supports_credentials': True, 'allow_headers': ['Content-Type', 'Cookie'] # 按需添加允许的请求头 } else: # 非可信来源:允许所有/指定来源,关闭凭证支持 return { 'origins': '*', # 生产环境建议替换为具体非可信来源列表 'supports_credentials': False } # 为所有接口应用动态CORS配置 CORS(app, resources={r"/*": dynamic_cors_config}) @app.route('/api/protected') def protected_api(): # 仅可信来源能携带Cookie,这里可获取并使用 user_token = request.cookies.get('user_token') return {"status": "success", "user_token": user_token}
方式二:自定义WSGI中间件(不依赖第三方扩展)
如果不想用Flask-CORS,可自行编写中间件处理CORS响应头:
from flask import Flask, request app = Flask(__name__) TRUSTED_ORIGINS = ["https://trusted-domain1.com", "https://trusted-domain2.com"] class CORSMiddleware: def __init__(self, app): self.app = app def __call__(self, environ, start_response): origin = environ.get('HTTP_ORIGIN') # 处理浏览器预请求(OPTIONS方法) if environ['REQUEST_METHOD'] == 'OPTIONS': base_headers = [ ('Content-Type', 'text/plain'), ('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS') ] if origin in TRUSTED_ORIGINS: trusted_headers = [ ('Access-Control-Allow-Origin', origin), ('Access-Control-Allow-Credentials', 'true'), ('Access-Control-Allow-Headers', 'Content-Type, Cookie') ] start_response('200 OK', base_headers + trusted_headers) else: untrusted_headers = [ ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'false') ] start_response('200 OK', base_headers + untrusted_headers) return [b''] # 处理正常请求,添加CORS响应头 response = self.app(environ, start_response) if origin in TRUSTED_ORIGINS: response.headers['Access-Control-Allow-Origin'] = origin response.headers['Access-Control-Allow-Credentials'] = 'true' else: response.headers['Access-Control-Allow-Origin'] = '*' response.headers['Access-Control-Allow-Credentials'] = 'false' return response # 挂载中间件 app.wsgi_app = CORSMiddleware(app.wsgi_app) @app.route('/api/protected') def protected_api(): user_token = request.cookies.get('user_token') return {"status": "success", "user_token": user_token}
关键注意事项
- 浏览器禁止同时设置
Access-Control-Allow-Origin: *和Access-Control-Allow-Credentials: true,因此可信来源必须返回具体的Origin值,不能用通配符。 - 生产环境建议避免用
*作为非可信来源的允许值,尽量明确列出所有允许的非可信域名,降低安全风险。 - 如果接口需要接收自定义请求头,需在
Access-Control-Allow-Headers中添加对应的头名称。
内容的提问来源于stack exchange,提问作者Baama
相关产品推荐
相关产品推荐

