我們開發的每個系統都離不開配置信息,例如數據庫密碼、Redis密碼、郵件配置、各種第三方配置信息,這些信息都非常敏感,一旦泄露出去后果非常嚴重,被泄露的原因一般是程序員將配置信息和代碼混在一起導致的。 判斷一個系統是否正確地將配置排除在代碼之外,一個簡單的方法是看該系統的代碼是否可以立刻開源,而不用擔心會暴露任何敏感信息。 所以我們做的第一件事情就是將配置信息與代碼解耦,根據不同的部署環境(開發環境、測試環境、預發布、生產環境)各使用一套配置文件,然后將配置信息集中到配置文件中。 例如在 django 最佳實踐里面,就有這種做法,每個部署環境都有一個獨立的配置文件,因為每個部署環境所需要的配置各不相同。 ```python ├── settings │ ├── __init__.py │ ├── base.py │ ├── local.py │ ├── production.py │ └── test.py ``` 系統啟動的時候,根據指定的環境變量決定加載哪個配置文件。 ```python if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.local") ``` 這樣就完了嗎? 不,因為配置信息還是和項目代碼捆綁在一起,如果配置文件與代碼同步到版本控制系統又擔心敏感信息泄露。 前面只是將配置與代碼解耦,但是代碼與敏感配置信息並沒有完全隔離。 一個更好的辦法就是將配置存儲於環境變量中,環境變量可以非常方便地在不同的部署間做修改,卻不動一行代碼,而這些信息同步到代碼庫的概率微乎其微。 在代碼中我們通過讀取環境變量中的配置信息來獲取該值。 ```python settings.py MAIL_SERVER = os.getenv('MAIL_SERVER') MAIL_USERNAME = os.getenv('MAIL_USERNAME') MAIL_PASSWORD = os.getenv('MAIL_PASSWORD') ``` 現在哪怕代碼開源出去,也沒人知道密碼是什么。 將配置信息保存在變量環境中,有好幾種方式,一種就是手動在命令行挨個設置到環境變量中,類似於: ```python EXPORT SECRET_KEY=xxxxx EXPORT SQLALCHEMY_DATABASE_URI=XXXX EXPORT ACCESSKEYID=XXXXX ``` 這種方式很麻煩,每次啟動都需要設,雖然你也可以寫到類似 .bashrc 這樣的文件中。 第二種方式是把配置信息寫在supervisor中,如果你的系統是用supervisor來管理進程的話,supervisor 中可以設置環境變量,如: ```python [program:xxxx] environment= KEY=value, Key2=value2, key3="val.&" ``` 但是這種方式與 supervisor 的本身配置耦合在一起,用起來比較混亂。 而今天推薦的這個工具 `python-dotenv` 就可以完全獨立於其它配置,只針對應用本身使用的配置信息,你只需要把配置信息全部寫入到項目根目錄的 `.env` 文件中 例如這樣: ``` REDIS_ADDRESS=localhost:6379 MEANING_OF_LIFE=42 MULTILINE_VAR="hello\nworld" ``` 這個文件我們不放在git版本控制系統中。然后用一行代碼來加載配置信息到環境變量中 ```python # settings.py from dotenv import load_dotenv load_dotenv() ``` 加載完成后就可以通過 `os.getenv` 方法去獲取所有的配置信息。 ```python # settings.py import os SECRET_KEY = os.getenv("EMAIL") DATABASE_PASSWORD = os.getenv("DATABASE_PASSWORD") ``` 這樣就完全將敏感信息脫離於代碼,同時代碼與配置也進行了解耦。 python-dov 的安裝用普通的pip安裝即可 ```python pip install -U python-dotenv ``` 這種使用方式在 django、flask 應用開發中很常見,而且他們基於此庫也做了自己的擴展,例如 flask 中可以用 `.flaskenv` 來代替 `.env` 文件。 無