diff --git a/ninja_apikey/admin.py b/ninja_apikey/admin.py index cfc727a..e251dde 100644 --- a/ninja_apikey/admin.py +++ b/ninja_apikey/admin.py @@ -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"] @@ -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 diff --git a/ninja_apikey/models.py b/ninja_apikey/models.py index 6bac925..f0bde13 100644 --- a/ninja_apikey/models.py +++ b/ninja_apikey/models.py @@ -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" diff --git a/ninja_apikey/security.py b/ninja_apikey/security.py index fabce0f..0e38e21 100644 --- a/ninja_apikey/security.py +++ b/ninja_apikey/security.py @@ -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") @@ -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 @@ -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 @@ -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