From a945c10ddf3142fa479e2df7f0daf9a96af49499 Mon Sep 17 00:00:00 2001 From: WellingtonLFaria Date: Thu, 26 Sep 2024 20:34:04 -0300 Subject: [PATCH] func: Autenticacao de usuario --- src/tupan/tupan/settings.py | 12 ++++++++++++ src/tupan/tupan/urls.py | 5 ++++- src/tupan/tupan/views.py | 15 +++++++++++++++ src/tupan/usuarios/admin.py | 5 ++++- src/tupan/usuarios/backends.py | 13 +++++++++++++ src/tupan/usuarios/models.py | 21 +++++++++++++++++---- src/tupan/usuarios/serializer.py | 12 ++++++------ src/tupan/usuarios/views.py | 10 ++++++++++ 8 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 src/tupan/tupan/views.py create mode 100644 src/tupan/usuarios/backends.py diff --git a/src/tupan/tupan/settings.py b/src/tupan/tupan/settings.py index f9b85fd..b24bd0f 100644 --- a/src/tupan/tupan/settings.py +++ b/src/tupan/tupan/settings.py @@ -47,6 +47,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', + 'rest_framework.authtoken', 'alertas', 'estacoes', 'drf_spectacular', @@ -55,8 +56,19 @@ REST_FRAMEWORK = { 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.TokenAuthentication', + ], + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + ], } +AUTHENTICATION_BACKENDS = [ + 'usuarios.backends.EmailBackend', + 'django.contrib.auth.backends.ModelBackend', +] + SPECTACULAR_SETTINGS = { 'TITLE': 'Tupã API', 'DESCRIPTION': '', diff --git a/src/tupan/tupan/urls.py b/src/tupan/tupan/urls.py index ea677b8..ae7f5c8 100644 --- a/src/tupan/tupan/urls.py +++ b/src/tupan/tupan/urls.py @@ -17,13 +17,16 @@ from django.contrib import admin from django.urls import include, path from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView +from rest_framework.authtoken.views import obtain_auth_token +from django.contrib.auth import views as auth_views +from .views import CustomAuthToken urlpatterns = [ path('admin/', admin.site.urls), path('', include('estacoes.urls')), - path('admin/', admin.site.urls), path('api/schema/', SpectacularAPIView.as_view(), name='schema'), path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'), path('usuarios/', include('usuarios.urls')), + path('api-token-auth/', CustomAuthToken.as_view(), name='api_token_auth'), ] diff --git a/src/tupan/tupan/views.py b/src/tupan/tupan/views.py new file mode 100644 index 0000000..ade709a --- /dev/null +++ b/src/tupan/tupan/views.py @@ -0,0 +1,15 @@ +from rest_framework.authtoken.views import ObtainAuthToken +from rest_framework.authtoken.models import Token +from rest_framework.response import Response +from django.contrib.auth import authenticate + +class CustomAuthToken(ObtainAuthToken): + def post(self, request, *args, **kwargs): + email = request.data.get('email') + password = request.data.get('password') + user = authenticate(request, username=email, password=password) + if user is not None: + token, created = Token.objects.get_or_create(user=user) + return Response({'token': token.key}) + else: + return Response({'error': 'Invalid Credentials'}, status=400) \ No newline at end of file diff --git a/src/tupan/usuarios/admin.py b/src/tupan/usuarios/admin.py index b04419f..6450efa 100644 --- a/src/tupan/usuarios/admin.py +++ b/src/tupan/usuarios/admin.py @@ -3,4 +3,7 @@ @admin.register(Usuario) class UsuarioAdmin(admin.ModelAdmin): - list_display = ('email', 'password') \ No newline at end of file + list_display = ('email', 'is_staff', 'is_superuser', 'ativo', 'criacao', 'alterado') + search_fields = ('email',) + readonly_fields = ('criacao', 'alterado') + ordering = ('email',) \ No newline at end of file diff --git a/src/tupan/usuarios/backends.py b/src/tupan/usuarios/backends.py new file mode 100644 index 0000000..efea137 --- /dev/null +++ b/src/tupan/usuarios/backends.py @@ -0,0 +1,13 @@ +from django.contrib.auth.backends import ModelBackend +from django.contrib.auth import get_user_model + +class EmailBackend(ModelBackend): + def authenticate(self, request, username=None, password=None, **kwargs): + UserModel = get_user_model() + try: + user = UserModel.objects.get(email=username) + except UserModel.DoesNotExist: + return None + if user.check_password(password) and self.user_can_authenticate(user): + return user + return None \ No newline at end of file diff --git a/src/tupan/usuarios/models.py b/src/tupan/usuarios/models.py index 0624ef8..01e2ac3 100644 --- a/src/tupan/usuarios/models.py +++ b/src/tupan/usuarios/models.py @@ -13,10 +13,16 @@ def create_user(self, email, password=None, **extra_fields): user.set_password(password) user.save(using=self._db) return user - + def create_superuser(self, email, password=None, **extra_fields): extra_fields.setdefault('is_superuser', True) extra_fields.setdefault('is_staff', True) + + if extra_fields.get('is_superuser') is not True: + raise ValueError('Superuser must have is_superuser=True.') + if extra_fields.get('is_staff') is not True: + raise ValueError('Superuser must have is_staff=True.') + return self.create_user(email, password, **extra_fields) class Usuario(AbstractBaseUser, PermissionsMixin): @@ -31,11 +37,18 @@ class Usuario(AbstractBaseUser, PermissionsMixin): objects = UsuarioManager() USERNAME_FIELD = 'email' - REQUIRED_FIELDS = ['password'] + REQUIRED_FIELDS = [] class Meta: verbose_name = "Usuário" verbose_name_plural = "Usuários" - - def __str__(self): return self.email + + def __str__(self): + return self.email + + def get_full_name(self): + return self.email + + def get_short_name(self): + return self.email \ No newline at end of file diff --git a/src/tupan/usuarios/serializer.py b/src/tupan/usuarios/serializer.py index ad2bbf2..d31ee62 100644 --- a/src/tupan/usuarios/serializer.py +++ b/src/tupan/usuarios/serializer.py @@ -1,12 +1,12 @@ from rest_framework import serializers -from usuarios.models import Usuario +from .models import Usuario -class UsuarioSerializer(serializers.HyperlinkedModelSerializer): +class UsuarioSerializer(serializers.ModelSerializer): class Meta: model = Usuario - fields = ['id', 'email', 'password', 'ativo', 'criacao', 'alterado'] + fields = ['id', 'email', 'password', 'criacao', 'alterado'] extra_kwargs = {'password': {'write_only': True}} - def create(self, validated_data): - user = Usuario.objects.create_user(**validated_data) - return user \ No newline at end of file + def create(self, validated_data): + user = Usuario.objects.create_user(**validated_data) + return user \ No newline at end of file diff --git a/src/tupan/usuarios/views.py b/src/tupan/usuarios/views.py index d578b62..8fed8f9 100644 --- a/src/tupan/usuarios/views.py +++ b/src/tupan/usuarios/views.py @@ -4,11 +4,21 @@ from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status +from rest_framework.permissions import IsAuthenticated, AllowAny class UsuarioList(APIView): """ Lista, cria, atualiza e deleta os usuários. """ + def get_permissions(self): + if self.request.method in ['DELETE', 'PUT']: + self.permission_classes = [IsAuthenticated] + elif self.request.method == 'POST': + self.permission_classes = [AllowAny] + else: + self.permission_classes = [IsAuthenticated] + return super().get_permissions() + def get(self, request, format=None): usuarios = Usuario.objects.all().filter(ativo=True) serializer = UsuarioSerializer(usuarios, many=True)