You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase Cloud Messaging(FCM)+Django:如何安全存储服务账号私钥?

解决Django中FCM服务账号JSON无法存入环境变量的问题

我之前也碰到过这个头疼的问题——官方文档要求用完整的服务账号JSON文件,但咱们习惯用环境变量管理敏感信息,确实没法直接把整个文件塞进去。下面给你几个实用的解决思路:

方法1:把JSON内容转成字符串存入环境变量,代码中解析

这是最直接的方案,步骤很简单:

  1. 打开你的FCM服务账号JSON文件,把所有内容复制成一个字符串(换行可以保留,Python能正常解析)
  2. 在环境变量里新增FCM_SERVICE_ACCOUNT_JSON,把刚才的字符串粘贴进去
  3. 在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_TYPE
  • FCM_PROJECT_ID
  • FCM_PRIVATE_KEY_ID
  • FCM_PRIVATE_KEY(注意这个字段里的换行要转义成\n,或者在环境变量里保留实际换行)
  • FCM_CLIENT_EMAIL
  • FCM_CLIENT_ID
  • FCM_AUTH_URI
  • FCM_TOKEN_URI
  • FCM_AUTH_PROVIDER_X509_CERT_URL
  • FCM_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:19:17