FLask 初探三( 隐藏配制文件实践 )

引言

Flask初探一(Flask 各参数的应用) 中提到了隐藏重要配置( 敏感配置) 的方式, 今天详细研究一下怎么样实现.

创建项目

项目结构

01-测试目录结构.png

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


  1. 配置的最佳实践 ↩

你可能感兴趣的:(FLask 初探三( 隐藏配制文件实践 ))