-
Notifications
You must be signed in to change notification settings - Fork 3
/
backends.py
75 lines (57 loc) 路 2.65 KB
/
backends.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import typing
from django.contrib.auth.backends import BaseBackend
from django.http import HttpRequest
from django.utils.timezone import now
from rest_framework import exceptions
from rest_framework_simple_api_key.crypto import ApiKeyCrypto
from rest_framework_simple_api_key.models import APIKey
from rest_framework_simple_api_key.parser import APIKeyParser
class APIKeyAuthentication(BaseBackend):
model = APIKey
key_parser = APIKeyParser()
key_crypto = ApiKeyCrypto()
def get_key(self, request: HttpRequest) -> typing.Optional[str]:
return self.key_parser.get(request)
def authenticate(self, request, **kwargs):
"""
The `authenticate` method is called on every request regardless of
whether the endpoint requires api key authentication.
`authenticate` has two possible return values:
1) `None` - We return `None` if we do not wish to authenticate. Usually
this means we know authentication will fail. An example of
this is when the request does not include an api key in the
headers.
2) `(entity)` - We return an entity object when
authentication is successful.
If neither case is met, that means there's an error,
and we do not return anything.
We simply raise the `AuthenticationFailed`
exception and let Django REST Framework
handle the rest.
"""
key = self.get_key(request)
return self._authenticate_credentials(request, key)
def _authenticate_credentials(self, request, key):
key_crypto = self.key_crypto
try:
payload = key_crypto.decrypt(key)
except ValueError:
raise exceptions.AuthenticationFailed("Invalid API Key.")
if "_pk" not in payload or "_exp" not in payload:
raise exceptions.AuthenticationFailed("Invalid API Key.")
if payload["_exp"] < now().timestamp():
raise exceptions.AuthenticationFailed("API Key has already expired.")
try:
api_key = self.model.objects.get(id=payload["_pk"])
except APIKey.DoesNotExist: # pylint: disable=maybe-no-member
raise exceptions.AuthenticationFailed("No entity matching this api key.")
if api_key.revoked:
raise exceptions.AuthenticationFailed("This API Key has been revoked.")
return api_key.entity, key
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass