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

如何在Django中实现需API Key和Secret的身份验证?

Django REST Framework API Key+Secret身份验证实现方案

rest_framework_api_key本身为单密钥设计,仅支持API Key校验,可通过以下两种方案实现双密钥校验逻辑:

方案1:扩展rest_framework_api_key库实现

通过扩展库的基类添加Secret校验能力,复用库原有API Key校验、前缀匹配等成熟能力:

  • 第一步:自定义带Secret的密钥模型
from django.db import models
from rest_framework_api_key.models import BaseAPIKey
import hashlib
import secrets

class APIKeyWithSecret(BaseAPIKey):
    secret_hash = models.CharField(max_length=128)
    user = models.ForeignKey("auth.User", on_delete=models.CASCADE, null=True)
    expired_at = models.DateTimeField(null=True, blank=True)

    # 封装密钥生成逻辑,仅生成时返回明文给用户
    @classmethod
    def generate_key_pair(cls, **kwargs):
        api_key, key_obj = cls.objects.create_key(**kwargs)
        # 生成16位随机Secret,长度可按需调整
        secret = secrets.token_urlsafe(16)
        key_obj.secret_hash = hashlib.sha256(secret.encode()).hexdigest()
        key_obj.save()
        return api_key, secret
  • 第二步:自定义认证类,添加Secret校验逻辑
from rest_framework import exceptions
from rest_framework_api_key.authentication import BaseAPIKeyAuthentication
from .models import APIKeyWithSecret
import hashlib
from datetime import datetime

class APIKeySecretAuthentication(BaseAPIKeyAuthentication):
    model = APIKeyWithSecret

    def authenticate(self, request):
        api_key = request.META.get("HTTP_X_API_KEY")
        api_secret = request.META.get("HTTP_X_API_SECRET")
        
        if not api_key or not api_secret:
            return None
        
        # 校验API Key前缀匹配
        prefix = api_key.split(".")[0] if "." in api_key else ""
        key_obj = self.model.objects.filter(prefix=prefix).first()
        if not key_obj:
            raise exceptions.AuthenticationFailed("无效的身份凭证")
        
        # 校验API Key有效性、过期时间
        if not key_obj.is_valid(api_key):
            raise exceptions.AuthenticationFailed("API Key已失效")
        if key_obj.expired_at and key_obj.expired_at < datetime.now():
            raise exceptions.AuthenticationFailed("API Key已过期")
        
        # 校验Secret哈希
        input_secret_hash = hashlib.sha256(api_secret.encode()).hexdigest()
        if input_secret_hash != key_obj.secret_hash:
            raise exceptions.AuthenticationFailed("无效的身份凭证")
        
        return (key_obj.user, key_obj)
  • 第三步:在settings.py中配置认证类
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "your_app.authentication.APIKeySecretAuthentication",
        # 其他原有认证类
    ]
}

方案2:无第三方依赖的自定义实现

如果不想引入rest_framework_api_key依赖,可自行完整实现整套逻辑:

  • 自建API密钥模型,存储密钥前缀、Key哈希、Secret哈希、权限范围、过期时间等字段
  • 自定义继承rest_framework.authentication.BaseAuthentication的认证类,实现和方案1一致的校验逻辑即可
  • 自行封装密钥生成、吊销、轮换的管理接口

注意事项

  • 所有敏感凭证禁止明文存储,API Key和Secret仅在生成时返回一次明文给用户,后台仅存储对应哈希值
  • 生产环境必须使用HTTPS传输请求,避免密钥被劫持
  • 可额外添加请求签名校验:客户端用Secret对请求参数、时间戳、请求路径等内容做签名,服务端校验签名一致性,进一步提升安全性
  • 建议添加密钥自动过期、手动轮换的机制,降低泄露风险

内容的提问来源于stack exchange,提问作者bballboy8

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 12:15:03