使用唯一的 SECRET_KEY 分发 Django 项目

我有一个 Django 项目,我想在公共存储库(如 bitbucket 或 github)上分发。我希望它尽可能容易安装,所以我包括完整的项目,而不只是可插拔的应用程序。这意味着也将包含 settings.py文件。

如何避免 settings.SECRET_KEY对于每个安装都是相同的问题?

是唯一的 很简单解决方案,让用户手动修改 settings.py

我是否应该将密钥存储在默认数据库中,如果它不存在,应该让 settings.py初始化它?这将解决问题,但我想知道是否已经有一个标准的方法来做到这一点。

谢谢!

29814 次浏览

一般来说,可以将 Django 配置分为应用程序特定的配置和服务器特定的配置。这属于后一类。

有许多方法可以解决特定于服务器的配置问题,这在 这个问题中有更多的讨论。

对于这个特殊的实例,使用我在回答另一个问题时概述的方法,我将在 settings_local.py.sample中放置一个占位符用于分发,在安装过程中,我将把它复制到 settings_local.py并进行编辑以适应。

我会这么做:

将密钥放在单独的文件“ secret _ key.py”中。对于原始安装,此文件不存在。在您的设置中,py 包含以下内容:

try:
from .secret_key import SECRET_KEY
except ImportError:
SETTINGS_DIR = os.path.abspath(os.path.dirname(__file__))
generate_secret_key(os.path.join(SETTINGS_DIR, 'secret_key.py'))
from .secret_key import SECRET_KEY

您将编写的函数 generate_secret_key(filename)将生成一个名为 filename的文件(我们称之为 filename,它将是与 settings.py在同一目录中的 secret_key.py) ,其内容如下:

SECRET_KEY = '....random string....'

其中随机字符串是基于随机数生成的键。

对于键生成,您可以使用 Umang 的建议 https://stackoverflow.com/a/16630719/166761

为了补充 Carles Barrobés所说的内容,您可以使用 Django 在 startproject中使用的方法生成一个新的密钥:

from django.utils.crypto import get_random_string


chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
get_random_string(50, chars)

对于 Django 1.10及以上版本,上面的代码片段被很好地包装在一个函数中。

from django.core.management.utils import get_random_secret_key
get_random_secret_key()

链接到 GitHub 回购

我会这样解决问题:

  • 提供一个虚拟的密钥,如: I_AM_A_DUMMY_KEY_CHANGE_ME
  • 创建一个命令来生成一个新的命令: ./manage.py gen_secret_key
  • 在文档中,STRONLY 建议用户尽快运行该命令

在我的代码中,我有三个级别的设置文件的灵感来自于 Two Scoops of Django,所以中间的一个是这样的,其中 BASE _ PRIVATE _ DIR 是在基本模板中设置的。在我的示例中,这来自 django 目录。./../mysite _ private,但在应用程序 git 下的正常文件之外:

from .base import *


ALLOWED_HOSTS = ['staging.django.site']
#Allow local override which is per deployment instance.  There should probably then be
#  an instance git for version control of the production data
try:
import sys
private_path = BASE_PRIVATE_DIR.child('production')
sys.path.append(private_path)
from private_settings import *
except ImportError:
print(" No production overide private_settings.py found.  This is probably an error  = {}".format(private_path))
# If it doesnt' exist that is fine and just use system and environment defaults

如果您使用模板创建一个新的项目,比如 django-admin.py startproject --template=path_to_template project_name,只需将 \{\{ secret_key }}放入您的项目模板设置文件(例如 setings.py) ,比如 SECRET_KEY = '\{\{ secret_key }}',Django 将为您生成它。

在这个解决方案中,我使用 Django-dotenv,它是我的项目的依赖项之一,如 requirements.txt中所列的 django-dotenv==1.4.1。这种方法的优点是,对于安装应用程序的每个环境,都有一个不同的 .env文件。

settings.py的同一目录中创建文件 utils.py,其内容如下:

from django.utils.crypto import get_random_string


def generate_secret_key(env_file_name):
env_file = open(env_file_name, "w+")
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
generated_secret_key = get_random_string(50, chars)
env_file.write("SECRET_KEY = '{}'\n".format(generated_secret_key))
env_file.close()

然后修改 settings.py文件如下:

import dotenv
from [project-folder-name] import utils
...
try:
SECRET_KEY = os.environ['SECRET_KEY']
except KeyError:
path_env = os.path.join(BASE_DIR, '.env')
utils.generate_secret_key(path_env)
dotenv.read_dotenv(path_env)
SECRET_KEY = os.environ['SECRET_KEY']

对于那些不使用 django-dotenv的人来说,你所要做的就是将它作为一个依赖项添加进来,然后在启动时更改 manage.py来加载它:

import dotenv


if __name__ == "__main__":
dotenv.read_dotenv()

python manage.py shell打开一个 Django shell,然后执行以下操作,在 Django 2.1中创建一个安全的随机密钥:

>>> from django.core.management.utils import get_random_secret_key
>>> get_random_secret_key()
'[GENERATED KEY]'
>>>

注意: >>>代表 shell 提示符,不应该输入。

编辑: 这里的一些答案建议从 Django 设置文件本身自动生成一个包含密钥的文件。由于以下几个原因,这不适合于生产环境。首先,将来部署到新机器时会产生不匹配的键。其次,您需要格外小心,以确保不能从其他程序或用户读取该文件。基于这些原因。

Carles Barrobés 给出了一个很好的答案,但是这个答案并不完整,这里是我对 python 3的版本,缺少了一个可以工作的函数。

from django.core.management.utils import get_random_secret_key


def generate_secret_key (filepath):
secret_file = open(filepath, "w")
secret = "SECRET_KEY= " + "\""+ get_random_secret_key() + "\"" + "\n"
secret_file.write(secret)
secret_file.close()


try:
from .secret_key import SECRET_KEY
except ModuleNotFoundError:


SETTINGS_DIR = os.path.abspath(os.path.dirname(__file__))
generate_secret_key(os.path.join(SETTINGS_DIR, 'secret_key.py'))
from .secret_key import SECRET_KEY

请注意,我修改了 ModuleNotFoundErrorImportError,并创建了 python 文件 secret_key.py,以像变量一样收集 SECRET _ KEY,而不是解析 txt 文件。

我在 Pypi.org上找到了这个代码块,它的工作原理几乎和 Umang 的答案一样。

在您的项目目录中运行

python manage.py generate_secret_key [--replace] [secretkey.txt]

这将生成一个包含随机 Django 密钥的新文件 secretkey.txt。在生产设置文件中,用生成的密钥替换密钥。

或者为了避免硬编码密钥。添加下面的代码片段,以便当您始终运行程序时,一个新的密钥将为您生成一个更新的密钥。

import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))


# Use a separate file for the secret key
with open(os.path.join(BASE_DIR, 'secretkey.txt')) as f:
SECRET_KEY = f.read().strip()

或者

# Use a separate file for the secret key
with open('/path/to/the/secretkey.txt') as f:
SECRET_KEY = f.read().strip()