Flask应用中如何安全获取数据库存储的Tokens与Keys?
问题描述
我开发了一个基于Flask和PostgreSQL的应用,企业的Tokens与Keys存储在companies表中,需要在应用的多个位置调用这些凭证。请问正确的实现方式是什么?是否有懒加载方案?
目前我尝试使用app.config(但不确定app_context或before_first_request的用法),示例代码如下:
with app.app_context(): if current_user: app.config["CURRENT_COMPANY_ID"] = current_user.company_id app.config["YANDEX_TOKEN"] =Company.query.filter_by(id=current_user.company_id).one().yandex_disk_token
或者使用g对象:
with app.app_context(): if current_user: g.company_id = current_user.company_id g.yandex_token =Company.query.filter_by(id=current_user.company_id).one().yandex_disk_token
但这些方法时常出现current_user为None或Company为None的错误,我不清楚该如何存储和获取这些Tokens与Keys,以确保仅登录用户可访问?
正确实现方案
1. 核心原则:禁用app.config存储用户/企业专属凭证
app.config是全局共享的配置容器,所有请求都会共用其中的内容。如果在这里存储某个用户的企业凭证,会导致并发请求时数据串用,完全不符合需求。必须使用请求级别的上下文对象g,它的生命周期和单个请求绑定,每个请求都有独立的g实例。
2. 结合请求钩子+登录验证加载凭证
使用Flask的before_request钩子,在每个请求处理前自动加载当前登录用户的企业凭证,同时必须先验证用户登录状态:
from flask import g, current_user from flask_login import login_required from your_app.models import Company @app.before_request def load_company_credentials(): # 初始化凭证为None,避免后续调用时出现属性不存在的错误 g.company_id = None g.yandex_token = None # 仅对已登录用户加载凭证 if current_user.is_authenticated: try: # 通过用户关联的企业ID查询企业,用get()避免查询不到时抛出异常 company = Company.query.get(current_user.company_id) if company: g.company_id = current_user.company_id g.yandex_token = company.yandex_disk_token except Exception as e: # 可添加日志记录异常,比如logging.error(f"加载企业凭证失败: {str(e)}") pass
同时,在所有需要使用凭证的路由上添加@login_required装饰器,确保只有登录用户能访问:
@app.route('/use-yandex-api') @login_required def use_yandex_api(): if not g.yandex_token: return "无法获取有效企业凭证", 403 # 调用Yandex API的逻辑 return "API调用成功"
3. 懒加载实现:按需查询数据库
如果不是所有请求都需要用到凭证,可以用懒加载的方式,只在需要时才查询数据库,减少不必要的DB请求:
from flask import g, current_user from your_app.models import Company def get_yandex_token(): # 检查g中是否已缓存凭证,没有则查询 if not hasattr(g, 'yandex_token') or g.yandex_token is None: g.yandex_token = None if current_user.is_authenticated: company = Company.query.get(current_user.company_id) if company: g.yandex_token = company.yandex_disk_token return g.yandex_token # 使用示例 @app.route('/use-yandex-api') @login_required def use_yandex_api(): token = get_yandex_token() if not token: return "无法获取有效企业凭证", 403 # 后续逻辑
4. 错误原因解析
current_user为None:你之前的代码用with app.app_context()手动创建上下文,但这只是应用上下文,没有请求上下文,current_user在非请求上下文中是无效的。必须在请求钩子或路由处理函数中操作,这些地方天然带有请求上下文,current_user才会正确指向当前登录用户(或匿名用户)。Company为None:直接用.one()查询企业,当不存在时会抛出异常,应该用.get()方法,查询不到时返回None,再做判断;另外要确保current_user.company_id是有效的(比如用户表和企业表的外键约束要正确)。
内容的提问来源于stack exchange,提问作者Константин Прудников
相关产品推荐
相关产品推荐

