jazzband / djangorestframework-simplejwt

A JSON Web Token authentication plugin for the Django REST Framework.
https://django-rest-framework-simplejwt.readthedocs.io/
MIT License
4.02k stars 663 forks source link

delete blacklist migrations #282

Closed mosi-kha closed 4 years ago

mosi-kha commented 4 years ago

hi please drop migrations folder in blacklist app, because when using djongo ODM and because not implement ALTER TABLE, in migrate has-error below :

FAILED SQL: ('ALTER TABLE "token_blacklist_blacklistedtoken" ADD COLUMN "token_id" int NOT NULL UNIQUE',)
Andrew-Chen-Wang commented 4 years ago

Hi @mosi-kha,

Sorry, I've seen an issue rise regarding Djongo before (which is the ODM for MongoDB, correct)? All I can really say is: I just don't support it. Imo, drop the shard/schema for this table and continue using SimpleJWT without the blacklist app. The blacklist app requires having database-backed tables to actually "blacklist" tokens.

So again, just don't use the blacklist app. It's a known issue for MongoDB devs that's not likely to be fixed in the near future. Apologies.

Duplicates #203

Andrew-Chen-Wang commented 4 years ago

Duplicate and stale

KzZe-Sama commented 2 years ago

Hello Is the issue resolved yet or anything I can do to black list a token using djongo. Any Help would be appreciated Thanks :D

mosi-kha commented 2 years ago

@KzZe-Sama hello I implement blacklist myself with cache, it's not a complicated scenario.

TWCM commented 2 years ago

@KzZe-Sama hello I implement blacklist myself with cache, it's not a complicated scenario.

Can you share your implementation?

abdi-bb commented 9 months ago

@mosi-kha hello Can you share how you implemented it?

mosi-kha commented 9 months ago

@abdi-bb @TWCM Hi guys, Apologies for the delay. I extended DRF IsAuthenticated class and used in permission_classes, implement like below:

from django.conf import settings
from rest_framework.permissions import BasePermission, IsAuthenticated, exceptions
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
from rest_framework_simplejwt.tokens import AccessToken
from .example.cache import UserSessionCache

class CustomIsAuthenticated(IsAuthenticated):
    def has_permission(self, request, view):
        is_authenticated = super().has_permission(request, view)

        if not is_authenticated:
            return is_authenticated
        try:
            access = AccessToken(request.auth.__str__())
            access_jti = access.get("jti")
            session_key = access.get("sid")
        except TokenError as e:
            raise InvalidToken(e.args[0])

        session_cache = UserSessionCache(session_key=session_key)
        session_data = session_cache.get()
        if not session_data or session_data.get("access_jti") != access_jti:
            raise exceptions.AuthenticationFailed("This session is expired.")
        return True

As you see i implemented a UserSessionCache too, in this class only save and delete with your cache tool(redis, ...), like:

from uuid import uuid4

from django.conf import settings
from example.cache import BaseCache

class UserSessionCache(BaseCache):
    key_prefix = "user_session:"
    timeout = settings.REFRESH_TOKEN_LIFETIME_SECONDS

    def __init__(self, session_key=None):
        if session_key is None:
            session_key = uuid4().hex
        super(UserSessionCache, self).__init__()
        self._session_key = session_key

    @property
    def session_key(self):
        return self._session_key

    def create(self, data: dict):
        """Create or update expire time of exist session
        """
        return self.client.set(
            key=self.make_key(self._session_key), value=data, timeout=self.timeout
        )

    def delete(self, session_key=None):
        _session_key = session_key
        if not _session_key:
            _session_key = self._session_key
        return self.client.delete(key=self.make_key(_session_key))

    def exist(self):
        return self.client.ttl(self.make_key(self._session_key)) == 0

    def get(self):
        return self.client.get(key=self.make_key(self._session_key))

Now with the help of the above, in your login and logout logics only need save and delete jwt sessions