Added sign-in view and simple protected view

This commit is contained in:
ITQ
2024-02-29 20:42:06 +03:00
parent fcf4499787
commit 2ea64e2bcb
6 changed files with 161 additions and 68 deletions
+6 -1
View File
@@ -112,7 +112,12 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
REST_FRAMEWORK = {
"DEFAULT_FILTER_BACKENDS": [
"django_filters.rest_framework.DjangoFilterBackend"
]
],
"DEFAULT_AUTHENTICATION_CLASSES": (
"users.authentication.JWTAuthentication",
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.BasicAuthentication",
),
}
APPEND_SLASH = False
+29
View File
@@ -0,0 +1,29 @@
import jwt
from django.conf import settings
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from users.models import Profile
class JWTAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.headers.get("Authorization", "").split("Bearer ")[-1]
if not token:
return None
try:
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=["HS256"]
)
user = Profile.objects.get(login=payload["login"])
return (user, None)
except Profile.DoesNotExist:
raise AuthenticationFailed("Invalid token")
except jwt.ExpiredSignatureError:
raise AuthenticationFailed("Token has expired")
except jwt.InvalidTokenError:
raise AuthenticationFailed("Invalid token")
+3
View File
@@ -34,5 +34,8 @@ class Profile(models.Model):
)
image = models.URLField(max_length=200, blank=True, null=True)
def is_authenticated(self):
return True
def __str__(self):
return self.login
+10 -1
View File
@@ -5,7 +5,16 @@ import users.views
urlpatterns = [
path(
"register",
users.views.register_user,
users.views.RegisterUserApiView.as_view(),
name="register",
),
path(
"sign-in",
users.views.SigninUserApiView.as_view(),
name="sign-in",
),
path(
"protected-view",
users.views.ProtectedView.as_view(),
)
]
+53 -7
View File
@@ -1,9 +1,14 @@
import re
from datetime import timedelta
import bcrypt
import jwt
from django.conf import settings
from django.utils import timezone
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from users.models import Profile
from users.serializers import UserSerializer
@@ -12,8 +17,8 @@ MIN_PASSWORD_LEN = 6
MAX_PASSWORD_LEN = 100
@api_view(["POST"])
def register_user(request):
class RegisterUserApiView(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
@@ -53,10 +58,10 @@ def register_user(request):
r"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{6,100}$"
)
if not (
bool(re.match(password_pattern, password))
):
error = {"message": "Your password does not meet our requirements"}
if not (bool(re.match(password_pattern, password))):
error = {
"message": "Your password does not meet our requirements"
}
return Response(
error,
status=status.HTTP_400_BAD_REQUEST,
@@ -85,3 +90,44 @@ def register_user(request):
return Response(profile, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class SigninUserApiView(APIView):
def post(self, request):
login = request.data.get("login")
password = request.data.get("password")
user = Profile.objects.filter(login=login).first()
if user is not None:
if not bcrypt.checkpw(
password.encode("utf-8"), user.password.encode("utf-8")
):
return Response(
{"error": "Invalid credentials"},
status=status.HTTP_401_UNAUTHORIZED,
)
else:
return Response(
{"error": "Invalid credentials"},
status=status.HTTP_401_UNAUTHORIZED,
)
token = jwt.encode(
{
"login": login,
"password": password,
"exp": timezone.now() + timedelta(hours=24),
},
settings.SECRET_KEY,
algorithm="HS256",
)
return Response({"token": token})
class ProtectedView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
user = request.user
return Response({"message": "Authenticated", "user": str(user)})
+1
View File
@@ -5,3 +5,4 @@ psycopg2-binary==2.9.9
dj-database-url==2.1.0
django-filter==23.5
bcrypt==4.1.2
djangorestframework-jwt==1.11.0