diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index d242094..cd8c7c8 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -14,6 +14,7 @@ services: - DBSCHEMA=desarrollo2 - DBUSER=postgres - DBPASS=password + - SECRET_JWT="kf6Jc!f30Z!1k1N0#!%#" ports: - 4000:4000 volumes: diff --git a/project/api/exceptions.py b/project/api/exceptions.py new file mode 100644 index 0000000..6aa16a1 --- /dev/null +++ b/project/api/exceptions.py @@ -0,0 +1,9 @@ +from rest_framework.exceptions import APIException + +class NotAuthorized(APIException): + status_code = 401 + default_detail = 'Acceso negado' + +class JWTExpired(APIException): + status_code = 400 + default_detail = 'Token ya no es valido' diff --git a/project/api/middlewares.py b/project/api/middlewares.py new file mode 100644 index 0000000..ae1bc2d --- /dev/null +++ b/project/api/middlewares.py @@ -0,0 +1,42 @@ +from django.http import HttpResponse +from .models import Usuario, Persona +import jwt +from decouple import config + +private_key = config('SECRET_JWT') + +class ApiMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + if not request.headers.get('Authorization') and request.path == '/api/auth/' and request.method == 'POST': + # cuando se quiere obtener el token, se omite esta regla + response = self.get_response(request) + return response + + authorization = request.headers.get('Authorization').split(' ') + token = authorization[1] + + try: + decoded = jwt.decode(token, private_key, algorithms=["HS256"]) + except jwt.ExpiredSignatureError: + return HttpResponse('token ya no es valido', status = 400) + except jwt.InvalidTokenError: + return HttpResponse('token es invalido', status = 400) + + usuario = Usuario.objects.filter(login = decoded['login'], vigente = True).values().first() + if not usuario: + return HttpResponse('Usuario ya no vigente', status = 400) + + persona = Persona.objects.filter(rut = usuario['rut_id']).values().first() + if not persona: + return HttpResponse('No existe información de la persona', status = 500) + + request.jwt_info = { + 'login': usuario['login'], + 'persona': persona + } + + response = self.get_response(request) + return response \ No newline at end of file diff --git a/project/api/serializers.py b/project/api/serializers.py index 819b837..6a0454c 100644 --- a/project/api/serializers.py +++ b/project/api/serializers.py @@ -1,7 +1,23 @@ from rest_framework import serializers from .models import Aplicacion +from .models import Usuario, Persona class AplicacionSerializer(serializers.ModelSerializer): class Meta: model = Aplicacion - fields = '__all__' \ No newline at end of file + fields = '__all__' + +class PersonaSerializer(serializers.ModelSerializer): + class Meta: + model = Persona + fields = '__all__' + +class UsuarioSerializer(serializers.ModelSerializer): + # persona = serializers.PrimaryKeyRelatedField(queryset=Persona.objects.all(), source='rut') + + class Meta: + model = Usuario + fields = ('login','vigente','rut') + + # def get_persona(self, usuario): + # return usuario.persona \ No newline at end of file diff --git a/project/api/urls.py b/project/api/urls.py index dc8caee..6d8e138 100644 --- a/project/api/urls.py +++ b/project/api/urls.py @@ -4,7 +4,10 @@ from api import views router = routers.DefaultRouter() router.register(r'aplicaciones', views.AplicacionViewSet) +router.register(r'usuarios', views.UsuarioViewSet) +router.register(r'personas', views.PersonaViewSet) urlpatterns = [ path('', include(router.urls)), + path(r'auth/', views.jwt_login, name='auth'), ] \ No newline at end of file diff --git a/project/api/views.py b/project/api/views.py index c0aaad3..30922e2 100644 --- a/project/api/views.py +++ b/project/api/views.py @@ -1,8 +1,56 @@ from rest_framework import viewsets +from rest_framework.decorators import action +from django.views.decorators.csrf import csrf_exempt +from django.http import HttpResponse +from django.http import JsonResponse +from .models import Usuario, Persona from .models import Aplicacion +from .serializers import UsuarioSerializer, PersonaSerializer from .serializers import AplicacionSerializer +import json +import jwt +import datetime +from decouple import config + +private_key = config('SECRET_JWT') # Create your views here. class AplicacionViewSet(viewsets.ModelViewSet): queryset = Aplicacion.objects.all() - serializer_class = AplicacionSerializer \ No newline at end of file + serializer_class = AplicacionSerializer + +class PersonaViewSet(viewsets.ModelViewSet): + queryset = Persona.objects.all() + serializer_class = PersonaSerializer + +class UsuarioViewSet(viewsets.ModelViewSet): + queryset = Usuario.objects.all() + serializer_class = UsuarioSerializer + +# Views jwt +@csrf_exempt +@action(detail=False, methods=['post','get']) +def jwt_login(request): + if request.method == 'POST': + # validar username y password + json_data = json.loads(request.body) + username = json_data['username'] + password = json_data['password'] + + usuario = Usuario.objects.filter(login = username, vigente = True).values().first() + if not usuario: + return HttpResponse('Acceso no valido', status = 400) + + if usuario['clave'] != password: + return HttpResponse('Acceso no valido', status = 400) + + now = datetime.datetime.utcnow() + payload = { + 'exp': now + datetime.timedelta(minutes=60), + 'login': usuario['login'] + } + token = jwt.encode(payload, private_key, algorithm="HS256") + return JsonResponse({ 'token': token }) + elif request.method == 'GET': + return JsonResponse(request.jwt_info) + \ No newline at end of file diff --git a/project/project/settings.py b/project/project/settings.py index bfd5d91..ae56f28 100644 --- a/project/project/settings.py +++ b/project/project/settings.py @@ -52,6 +52,8 @@ MIDDLEWARE = [ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'corsheaders.middleware.CorsMiddleware', + 'api.middlewares.ApiMiddleware', ] ROOT_URLCONF = 'project.urls' @@ -135,7 +137,7 @@ STATIC_URL = 'static/' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' REST_FRAMEWORK = { 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' } -CORS_ALLOW_CREDENTIALS = True -CORS_ALLOWED_ORIGINS = [ +CORS_ORIGIN_ALLOW_ALL = False +CORS_ORIGIN_WHITELIST = [ "http://localhost:3000", ] \ No newline at end of file diff --git a/rest/login.rest b/rest/login.rest new file mode 100644 index 0000000..eeeef0f --- /dev/null +++ b/rest/login.rest @@ -0,0 +1,17 @@ + +@server = http://localhost:4000/api +@token = {{login.response.body.$.token}} + +### +# @name login +POST {{server}}/auth/ +Content-Type: application/json + +{ + "username": "usuario1", + "password": "usuario1" +} + +### +GET {{server}}/auth/ +Authorization: Bearer {{token}} \ No newline at end of file