引言
Flask初探一(Flask 各参数的应用) 中提到了隐藏重要配置( 敏感配置) 的方式, 今天详细研究一下怎么样实现.
创建项目
项目结构
main.py
假设config_private 目录下的config_private.py是要隐藏的配置文件
导入模板 flask_migrate, flask_redis, flask_script, flask_session, flask_sqlalchemy
main.py
# 配置
from flask import Flask, session
from flask_migrate import Migrate, MigrateCommand
from flask_redis import redis
from flask_script import Manager
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
# app = Flask(__name__,
# instance_path="E:\\workspace\\pycharm\\demo\\config_private",
# instance_relative_config=True)
app = Flask(__name__)
class Config(object):
# debug
DEBUG = False
# SQLAlchemy
SQLALCHEMY_DATABASE_URI = "mysql://root:[email protected]:3306/fang"
SQLALCHEMY_TRACK_MODIFICATIONS = False
# redis
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 0
# session
SECRET_KEY = "EjpNVSNQTyGi1VvWECj9TvC/+kq3oujee2kTfQUs8yCM6xX9Yjq52v54g+HVoknA"
SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
SESSION_USE_SIGNER = True # 让 cookie 中的 session_id 被加密签名处理
PERMANENT_SESSION_LIFETIME = 60 * 60 * 24 * 7 # session 的有效期,单位是秒
app.config.from_object(Config)
redis = redis.StrictRedis(host=Config.REDIS_HOST,
port=Config.REDIS_PORT,
db=Config.REDIS_DB)
db_SQLAlchemy = SQLAlchemy(app)
Migrate(app, db_SQLAlchemy)
Session(app)
manager = Manager(app)
manager.add_command("db", MigrateCommand)
@app.route('/')
def index():
session["aa"] = "aa"
return 'index'
if __name__ == '__main__':
manager.run()
隐藏敏感信息
配置完成, 可以正常运行. 里面有一些账号密码 等敏感信息,不想公开, 怎么办?
首先, 将配置信息抽取到config_private.py 文件, 结合 配制的最佳实践[1]
config_private.py
class Config(object):
# debug
DEBUG = False
# SQLAlchemy
SQLALCHEMY_DATABASE_URI = "mysql://root:[email protected]:3306/fang"
SQLALCHEMY_TRACK_MODIFICATIONS = False
# redis
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 0
# session
SECRET_KEY = "EjpNVSNQTyGi1VvWECj9TvC/+kq3oujee2kTfQUs8yCM6xX9Yjq52v54g+HVoknA"
SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
SESSION_USE_SIGNER = True # 让 cookie 中的 session_id 被加密签名处理
PERMANENT_SESSION_LIFETIME = 60 * 60 * 24 * 7 # session 的有效期,单位是秒
class ProductionConfig(Config):
DEBUG = False
# redis
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 0
class DevelopmentConfig(Config):
DEBUG = True
# redis
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 0
配置信息抽取完成
从文件加载配置信息
实验
# 配置
from flask import Flask, session
from flask_migrate import Migrate, MigrateCommand
from flask_redis import redis
from flask_script import Manager
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
# app = Flask(__name__,
# instance_path="E:\\workspace\\pycharm\\demo\\config_private",
# instance_relative_config=True)
app = Flask(__name__)
app.config.from_pyfile("config_private.py")
redis = redis.StrictRedis(host=Config.REDIS_HOST,
port=Config.REDIS_PORT,
db=Config.REDIS_DB)
db_SQLAlchemy = SQLAlchemy(app)
Migrate(app, db_SQLAlchemy)
Session(app)
manager = Manager(app)
manager.add_command("db", MigrateCommand)
@app.route('/')
def index():
session["aa"] = "aa"
return 'index'
if __name__ == '__main__':
manager.run()
实验结果
Traceback (most recent call last):
File "E:/workspace/pycharm/demo/main.py", line 14, in
app.config.from_pyfile("config_private.py")
File "D:\software\Python\lib\site-packages\flask\config.py", line 128, in from_pyfile
with open(filename,encoding="UTF-8") as config_file:
FileNotFoundError: [Errno 2] Unable to load configuration file (No such file or directory): 'E:\\workspace\\pycharm\\demo\\config_private\\config_private.py'
没有指定文件或文件夹?instance_path 和 instance_relative_config 登场
instance_path 和 instance_relative_config
main.py
# 配置
from flask import Flask, session
from flask_migrate import Migrate, MigrateCommand
from flask_redis import redis
from flask_script import Manager
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__,
instance_path="E:\\workspace\\pycharm\\demo\\config_private",
instance_relative_config=True)
# app = Flask(__name__)
app.config.from_pyfile("config_private.py")
# 屏蔽一下,Config 类被抽取到config_private.py 文件了
# redis = redis.StrictRedis(host=Config.REDIS_HOST,
# port=Config.REDIS_PORT,
# db=Config.REDIS_DB)
db_SQLAlchemy = SQLAlchemy(app)
Migrate(app, db_SQLAlchemy)
Session(app)
manager = Manager(app)
manager.add_command("db", MigrateCommand)
@app.route('/')
def index():
session["aa"] = "aa"
return 'index'
if __name__ == '__main__':
manager.run()
实验结果
E:\workspace\pycharm\demo\venv\Scripts\python.exe E:/workspace/pycharm/demo/main.py runserver
D:\software\Python\lib\site-packages\flask_sqlalchemy\__init__.py:774: UserWarning: Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:".
'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. '
D:\software\Python\lib\site-packages\flask_sqlalchemy\__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning.
'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
什么情况? 配制不正确了?! 为什么呢?修改一下配置文件, 只保留一个配置
config_private.py
DEBUG = True
实验结果
* Restarting with stat
* Debugger is active!
* Debugger PIN: 213-569-008
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Debugger is active! 说明我们从文件引入配置是没问题的, 那么问题在哪? 问题在于from_object , 都没有出现过from_object, 为什么说问题出在他身上?
from_pyfile 源码
def from_pyfile(self, filename, silent=False):
filename = os.path.join(self.root_path, filename)
d = imp.new_module('config')
d.__file__ = filename
try:
with open(filename,encoding="UTF-8") as config_file:
exec(compile(config_file.read(), filename, 'exec'), d.__dict__)
except IOError as e:
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
return False
e.strerror = 'Unable to load configuration file (%s)' % e.strerror
raise
# 重点在这, from_pyfile 的本质也是通过from_object 添加配置信息
self.from_object(d)
return True
那么from_object 的问题是什么?
from_object 源码
def from_object(self, obj):
if isinstance(obj, string_types):
obj = import_string(obj)
for key in dir(obj):
# 重点在这
if key.isupper():
self[key] = getattr(obj, key)
key.isupper() , 键是全大写吗? 是就加入app.config 字典, 从这里可以看出来, 文件中的配置信息必须大写, 才能被添加到app.config 字典中, 不然, 你只能修改这句代码了.
实验
config_private.py
# 如果使用类, 请将类名关不大写, 不然需要改变源码,才能将属性放到app.config 字典中
class CONFIGPRIVATE(object):
# SQLAlchemy
SQLALCHEMY_DATABASE_URI = "mysql://root:[email protected]:3306" # TODO 敏感信息
SQLALCHEMY_TRACK_MODIFICATIONS = False
# Redis # TODO 敏感信息
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 0
# Session
"""
import base64,os
data = os.urandom(32)
print(base64.b64encode(data).decode("utf-8"))
"""
SECRET_KEY = "GwjkfXdUOa8bt4WwF0FgSbtCbbv9Wc8Aeny/SMEQ1+L5q/svnQhWubMOPITa1JU+ptprYf1RoFGys0Qana7XoQ==" # TODO 敏感信息
SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
SESSION_USE_SIGNER = True # 让 cookie 中的 session_id 被加密签名处理
PERMANENT_SESSION_LIFETIME = 60 * 60 * 24 * 7 # session 的有效期,单位是秒
class PRODUCTIONCONFIG(CONFIGPRIVATE):
# redis
REDIS_HOST = "192.168.70.45"
REDIS_PORT = 6379
REDIS_DB = 5
class DEVELOPMENTCONFIG(CONFIGPRIVATE):
# redis
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 1
class TESTINGCONFIG(CONFIGPRIVATE):
# redis
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 3
main.py
# 配置
from flask import Flask, session
from flask_migrate import MigrateCommand, Migrate
from flask_script import Manager
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__,
instance_path="E:\\workspace\\pycharm\\demo\\config_private",
instance_relative_config=True)
old_config = app.config
app.config.from_pyfile("config_private.py")
# redis = redis.StrictRedis(host=Config.REDIS_HOST,
# port=Config.REDIS_PORT,
# db=Config.REDIS_DB)
db_SQLAlchemy = SQLAlchemy(app)
Migrate(app, db_SQLAlchemy)
Session(app)
manager = Manager(app)
manager.add_command("db", MigrateCommand)
@app.route('/')
def index():
print(old_config)
print(app.config)
return 'index'
if __name__ == '__main__':
app.run()
实验结果
D:\software\Python\lib\site-packages\flask_sqlalchemy\__init__.py:774: UserWarning: Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:".
'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. '
D:\software\Python\lib\site-packages\flask_sqlalchemy\__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning.
'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '
, 'DEVELOPMENTCONFIG': , 'PRODUCTIONCONFIG': , 'TESTINGCONFIG': }>
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
虽然失败了, 但是可以看出两次的config 字典不同
正确姿势
言归正传,怎样正确隐藏敏感配置, 如果要使用文件并且通过类进行配置, 略微有些麻烦. 至于不使用文件不使用类的方式这里不做讨论, 配置DEBUG 属性就是一个使用文件,不使用类的最简单的例子
config_private.py
# 如果使用类, 请将类名关不大写, 不然需要改变源码,才能将属性放到app.config 字典中
class CONFIGPRIVATE(object):
DEBUG = False
# SQLAlchemy
SQLALCHEMY_DATABASE_URI = "mysql://root:[email protected]:3306" # TODO 敏感信息
SQLALCHEMY_TRACK_MODIFICATIONS = False
# Redis # TODO 敏感信息
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 0
# Session
"""
import base64,os
data = os.urandom(32)
print(base64.b64encode(data).decode("utf-8"))
"""
SECRET_KEY = "GwjkfXdUOa8bt4WwF0FgSbtCbbv9Wc8Aeny/SMEQ1+L5q/svnQhWubMOPITa1JU+ptprYf1RoFGys0Qana7XoQ==" # TODO 敏感信息
SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
SESSION_USE_SIGNER = True # 让 cookie 中的 session_id 被加密签名处理
PERMANENT_SESSION_LIFETIME = 60 * 60 * 24 * 7 # session 的有效期,单位是秒
class PRODUCTIONCONFIG(CONFIGPRIVATE):
DEBUG = False
# redis
REDIS_HOST = "192.168.70.45"
REDIS_PORT = 6379
REDIS_DB = 5
class DEVELOPMENTCONFIG(CONFIGPRIVATE):
DEBUG = True
# redis
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 1
class TESTINGCONFIG(CONFIGPRIVATE):
DEBUG = True
# redis
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 3
main.py
# 配置
import redis
from flask import Flask, session
from flask_migrate import MigrateCommand, Migrate
from flask_script import Manager
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__,
instance_path="E:\\workspace\\pycharm\\demo\\config_private\\",
instance_relative_config=True)
app.config.from_pyfile("config_private.py")
dev_config = app.config["DEVELOPMENTCONFIG"]
app.config.from_object(dev_config)
redis = redis.StrictRedis(host=dev_config.REDIS_HOST,
port=dev_config.REDIS_PORT,
db=dev_config.REDIS_DB)
db_SQLAlchemy = SQLAlchemy(app)
Migrate(app, db_SQLAlchemy)
Session(app)
manager = Manager(app)
manager.add_command("db", MigrateCommand)
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
app.run()
运行结果
# 配置
import redis
from flask import Flask, session
from flask_migrate import MigrateCommand, Migrate
from flask_script import Manager
from flask_session import Session
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__,
instance_path="E:\\workspace\\pycharm\\demo\\config_private\\",
instance_relative_config=True)
app.config.from_pyfile("config_private.py")
dev_config = app.config["DEVELOPMENTCONFIG"]
app.config.from_object(dev_config)
redis = redis.StrictRedis(host=dev_config.REDIS_HOST,
port=dev_config.REDIS_PORT,
db=dev_config.REDIS_DB)
db_SQLAlchemy = SQLAlchemy(app)
Migrate(app, db_SQLAlchemy)
Session(app)
manager = Manager(app)
manager.add_command("db", MigrateCommand)
@app.route('/')
def index():
return 'index'
if __name__ == '__main__':
app.run()
perfect ! 完美 !
到此结 DragonFangQy 2018.6.20
-
配置的最佳实践 ↩