如何在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
相关产品推荐
相关产品推荐

