Firebase Cloud Messaging(FCM)+Django:如何安全存储服务账号私钥?
解决Django中FCM服务账号JSON无法存入环境变量的问题
我之前也碰到过这个头疼的问题——官方文档要求用完整的服务账号JSON文件,但咱们习惯用环境变量管理敏感信息,确实没法直接把整个文件塞进去。下面给你几个实用的解决思路:
方法1:把JSON内容转成字符串存入环境变量,代码中解析
这是最直接的方案,步骤很简单:
- 打开你的FCM服务账号JSON文件,把所有内容复制成一个字符串(换行可以保留,Python能正常解析)
- 在环境变量里新增
FCM_SERVICE_ACCOUNT_JSON,把刚才的字符串粘贴进去 - 在Django代码里把这个字符串解析成字典,替代原来读取文件的逻辑:
import os import json from google.oauth2 import service_account import google.auth.transport.requests def _get_access_token(): """Retrieve a valid access token that can be used to authorize requests.""" # 从环境变量获取JSON字符串并解析为字典 service_account_json_str = os.environ.get('FCM_SERVICE_ACCOUNT_JSON') if not service_account_json_str: raise ValueError("FCM_SERVICE_ACCOUNT_JSON environment variable not set") service_account_info = json.loads(service_account_json_str) credentials = service_account.Credentials.from_service_account_info( service_account_info, scopes=['https://www.googleapis.com/auth/firebase.messaging'] ) request = google.auth.transport.requests.Request() credentials.refresh(request) return credentials.token
方法2:拆分JSON字段到单独的环境变量
如果觉得存整个字符串不太舒服,也可以把JSON里的敏感字段拆出来单独存,比如:
FCM_TYPEFCM_PROJECT_IDFCM_PRIVATE_KEY_IDFCM_PRIVATE_KEY(注意这个字段里的换行要转义成\n,或者在环境变量里保留实际换行)FCM_CLIENT_EMAILFCM_CLIENT_IDFCM_AUTH_URIFCM_TOKEN_URIFCM_AUTH_PROVIDER_X509_CERT_URLFCM_CLIENT_X509_CERT_URL
然后在代码中手动构建字典:
import os from google.oauth2 import service_account import google.auth.transport.requests def _get_access_token(): """Retrieve a valid access token that can be used to authorize requests.""" service_account_info = { "type": os.environ.get('FCM_TYPE'), "project_id": os.environ.get('FCM_PROJECT_ID'), "private_key_id": os.environ.get('FCM_PRIVATE_KEY_ID'), # 处理private_key里的换行转义 "private_key": os.environ.get('FCM_PRIVATE_KEY').replace('\\n', '\n'), "client_email": os.environ.get('FCM_CLIENT_EMAIL'), "client_id": os.environ.get('FCM_CLIENT_ID'), "auth_uri": os.environ.get('FCM_AUTH_URI'), "token_uri": os.environ.get('FCM_TOKEN_URI'), "auth_provider_x509_cert_url": os.environ.get('FCM_AUTH_PROVIDER_X509_CERT_URL'), "client_x509_cert_url": os.environ.get('FCM_CLIENT_X509_CERT_URL') } # 检查必填字段是否存在 required_fields = ["private_key", "client_email", "project_id"] for field in required_fields: if not service_account_info[field]: raise ValueError(f"FCM_{field.upper()} environment variable not set") credentials = service_account.Credentials.from_service_account_info( service_account_info, scopes=['https://www.googleapis.com/auth/firebase.messaging'] ) request = google.auth.transport.requests.Request() credentials.refresh(request) return credentials.token
额外注意事项
- 不管用哪种方法,都要确保环境变量内容不会泄露——别把
.env文件提交到Git仓库,生产环境用服务器自带的环境变量管理工具(比如Docker Secrets、AWS Secrets Manager) - 处理
private_key时一定要注意换行问题,如果环境变量里用\n代替了实际换行,必须在代码里替换回来,否则会导致认证失败 - 本地测试可以用
python-dotenv库加载.env文件,验证逻辑没问题再部署到生产环境
内容的提问来源于stack exchange,提问作者J. Hesters
相关产品推荐
相关产品推荐

