Dav*_*uth 6 python django python-2.7 django-rest-framework
我已经实现了一个网络钩子。调用者提供共享秘密。它们连接请求 URL 和正文,使用密钥对其进行签名,并在标头中提供签名。为了验证签名,我需要重复该过程并将我获得的签名与调用者获得的签名进行比较。
我正在使用 Django REST 框架。我正在检查自定义中的签名Authentication。框架以请求作为参数来调用Authentication的方法。authenticate我可以从 获取请求正文request.stream.read()。但是,这会消耗流,从而阻止框架为我解析它:当框架调用视图时,请求没有data像通常那样的属性。
request.stream不允许我这样做seek(0)。该请求不允许我用倒带流(例如StringIO. 我当前的解决方法是将主体存储在视图中request.auth并自己在视图中解析它,这有效但很丑陋。
有没有办法在 中安全地访问请求正文Authentication?
这是有效的版本:
在myapp/authentications.py:
import hmac
from hashlib import sha1
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class WebhookAuthentication(BaseAuthentication):
def authenticate(self, request):
actual_signature = request.META['X-Vendor-Signature']
body, expected_signature = self.expected_signature(request)
if actual_signature != expected_signature:
raise AuthenticationFailed("Request X-Vendor-Signature did not match expected signature")
return None, body # Hack: preserve the body in request.auth
def expected_signature(self, request):
body = request.stream.read()
raw = request.build_absolute_uri(request.META['PATH_INFO']) + body
signature = hmac.new("the shared secret", raw, sha1).digest().encode("base64")
return body, signature
Run Code Online (Sandbox Code Playgroud)
在myapp/views.py:
import json
from rest_framework.views import APIView
from serializers import SomeSerializer
from myapp.authentications import WebhookAuthentication
class SomeView(APIView):
authentication_classes = (WebhookAuthentication,)
permission_classes = ()
def post(self, request, _=None):
data = json.loads(request.auth) # Hack: get the body from where we stashed it
serializer = SomeSerializer(data=data) # I'd like to be able to use request.data here
# Use the serializer ...
Run Code Online (Sandbox Code Playgroud)
我怎样才能比黑客做得更好?