working on manual logout: block access token
This commit is contained in:
@@ -10,7 +10,7 @@ from apps.authentication.api.v1.serializers.serializer import (
|
||||
OrganizationTypeSerializer,
|
||||
OrganizationSerializer,
|
||||
UserSerializer,
|
||||
BankAccountSerializer
|
||||
BankAccountSerializer,
|
||||
)
|
||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
||||
from apps.authorization.api.v1 import api as authorize_view
|
||||
@@ -21,7 +21,8 @@ from apps.authentication.models import (
|
||||
Province,
|
||||
Organization,
|
||||
OrganizationType,
|
||||
BankAccountInformation
|
||||
BankAccountInformation,
|
||||
BlacklistedAccessToken
|
||||
)
|
||||
from django.db import transaction
|
||||
from rest_framework.response import Response
|
||||
@@ -30,6 +31,9 @@ from django.core.cache import cache
|
||||
from rest_framework import status
|
||||
from common.sms import send_sms
|
||||
import random
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from apps.authentication.tools import get_token_jti
|
||||
|
||||
|
||||
class CustomizedTokenObtainPairView(TokenObtainPairView):
|
||||
@@ -37,6 +41,24 @@ class CustomizedTokenObtainPairView(TokenObtainPairView):
|
||||
serializer_class = CustomizedTokenObtainPairSerializer
|
||||
|
||||
|
||||
class LogoutView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
token_str = request.auth # access token from header
|
||||
jti, user_id = get_token_jti(str(token_str))
|
||||
|
||||
if not jti:
|
||||
return Response({'detail': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
BlacklistedAccessToken.objects.get_or_create(jti=jti, defaults={
|
||||
'token': token_str,
|
||||
'user_id': user_id,
|
||||
})
|
||||
|
||||
return Response({'detail': 'Access token blacklisted.'}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class UserViewSet(ModelViewSet):
|
||||
""" Crud operations for user model """
|
||||
queryset = User.objects.all()
|
||||
|
||||
@@ -13,7 +13,8 @@ from .api import (
|
||||
ProvinceViewSet,
|
||||
OrganizationViewSet,
|
||||
OrganizationTypeViewSet,
|
||||
GeneralOTPViewSet
|
||||
GeneralOTPViewSet,
|
||||
LogoutView
|
||||
)
|
||||
|
||||
router = DefaultRouter()
|
||||
@@ -26,6 +27,7 @@ router.register(r'otp', GeneralOTPViewSet, basename='otp')
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', CustomizedTokenObtainPairView.as_view(), name='token_obtain_pair'),
|
||||
path('logout/', LogoutView.as_view(), name='logut'),
|
||||
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
||||
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
|
||||
path('token/revoke/', TokenBlacklistView.as_view(), name='revoke_token'),
|
||||
|
||||
9
apps/authentication/exceptions.py
Normal file
9
apps/authentication/exceptions.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from rest_framework.exceptions import APIException
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import status
|
||||
|
||||
|
||||
class TokenBlackListedException(APIException):
|
||||
status_code = status.HTTP_401_UNAUTHORIZED
|
||||
default_detail = _('unauthorized')
|
||||
default_code = 'unauthorized'
|
||||
25
apps/authentication/middlewares.py
Normal file
25
apps/authentication/middlewares.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from .models import BlacklistedAccessToken
|
||||
from apps.authentication.tools import get_token_jti
|
||||
from rest_framework.exceptions import AuthenticationFailed
|
||||
from apps.authentication.exceptions import TokenBlackListedException
|
||||
from rest_framework.response import Response
|
||||
from django.http import JsonResponse
|
||||
from rest_framework import status
|
||||
|
||||
|
||||
class BlockedTokenMiddleware:
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if auth_header and auth_header.startswith('Bearer '):
|
||||
token_str = auth_header[7:]
|
||||
jti, _ = get_token_jti(token_str)
|
||||
if jti and BlacklistedAccessToken.objects.filter(jti=jti).exists():
|
||||
return JsonResponse({
|
||||
'detail': 'Access token has been blacklisted'
|
||||
}, status=401)
|
||||
|
||||
return self.get_response(request)
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.0 on 2025-06-02 08:31
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authentication', '0019_organizationtype_code'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BlacklistedAccessToken',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('jti', models.CharField(max_length=255, unique=True)),
|
||||
('token', models.TextField()),
|
||||
('user_id', models.IntegerField()),
|
||||
('blacklisted_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -144,3 +144,13 @@ class BankAccountInformation(BaseModel):
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super(BankAccountInformation, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class BlacklistedAccessToken(models.Model):
|
||||
jti = models.CharField(max_length=255, unique=True)
|
||||
token = models.TextField()
|
||||
user_id = models.IntegerField()
|
||||
blacklisted_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"Blacklisted JTI: {self.jti}"
|
||||
|
||||
9
apps/authentication/tools.py
Normal file
9
apps/authentication/tools.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from rest_framework_simplejwt.tokens import AccessToken
|
||||
|
||||
|
||||
def get_token_jti(token_str):
|
||||
try:
|
||||
token = AccessToken(token_str)
|
||||
return token['jti'], token['user_id']
|
||||
except Exception as e:
|
||||
return None, None
|
||||
Reference in New Issue
Block a user