Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ninja_apikey/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class APIKeyAdmin(admin.ModelAdmin):
"revoked",
"is_active",
]
readonly_fields = ["prefix", "hashed_key", "created_at"]
readonly_fields = ["prefix", "hashed_key", "created_at", "key"]
actions = [revoke_key]
list_filter = ["revoked"]

Expand All @@ -33,6 +33,7 @@ def is_active(self, obj: APIKey):
def save_model(self, request, obj: APIKey, form, change):
if not obj.prefix: # New API key
key = generate_key()
obj.key = key.key
obj.prefix = key.prefix
obj.hashed_key = key.hashed_key

Expand Down
2 changes: 1 addition & 1 deletion ninja_apikey/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class APIKey(models.Model):
revoked = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
expires_at = models.DateTimeField(null=True, blank=True)

key = models.CharField(max_length=200)
class Meta:
ordering = ["-created_at"]
verbose_name = "API key"
Expand Down
45 changes: 38 additions & 7 deletions ninja_apikey/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
from django.contrib.auth.hashers import check_password, make_password
from django.http import HttpRequest
from django.utils.crypto import get_random_string
from ninja.security import APIKeyQuery
from ninja.security import APIKeyHeader


from .models import APIKey # type: ignore

KeyData = namedtuple("KeyData", "prefix key hashed_key")
Expand All @@ -18,7 +20,7 @@ def generate_key() -> KeyData:
return KeyData(prefix, key, hashed_key)


def check_apikey(api_key: str) -> Any:
def check_apikey(api_key: str, perm) -> Any:
if not api_key:
return False

Expand All @@ -31,7 +33,6 @@ def check_apikey(api_key: str) -> Any:
key = data[1]

persistent_key = APIKey.objects.filter(prefix=prefix).first()

if not persistent_key:
return False

Expand All @@ -42,24 +43,54 @@ def check_apikey(api_key: str) -> Any:
return False

user = persistent_key.user

if not user:
return False

if not user.is_active:
return False


# Additional checking for the view permission for the user
if perm and not user.has_perm(perm):
return False
return user

# Added the api key as a query option
class APIKeyAuthQuery(APIKeyQuery):
param_name = "api_key"

def __init__(self, param_name="api_key", perm="", *args, **kwargs) -> None:
self.param_name=param_name
self.perm = perm
super().__init__()

def authenticate(self, request: HttpRequest, key: Optional[str]) -> Any:
if not key:
return False

user = check_apikey(key, self.perm)

if not user:
return False

request.user = user
return user


class APIKeyAuth(APIKeyHeader):
param_name = "X-API-Key"
class APIKeyAuthHeader(APIKeyHeader):
param_name = "api_key"

def __init__(self, param_name="api_key", perm="", *args, **kwargs) -> None:
self.param_name=param_name
#Specify the key used in the url
self.perm = perm
#If use must have a certain permission to use thtat api
super().__init__()

def authenticate(self, request: HttpRequest, key: Optional[str]) -> Any:
if not key:
return False

user = check_apikey(key)
user = check_apikey(key, self.perm)

if not user:
return False
Expand Down