Added sign-in view and simple protected view
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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")
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
]
|
||||
|
||||
@@ -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)})
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user