se agrega compilacion de frontend y manejo de jwt
parent
a9579af488
commit
d860dad7ea
|
@ -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 = 'Acceso expiro'
|
|
@ -5,6 +5,7 @@ from .models import Project, Agency, Route
|
||||||
# serializers
|
# serializers
|
||||||
from .serializers import ProjectSerializer, AgencySerializer, RouteSerializer
|
from .serializers import ProjectSerializer, AgencySerializer, RouteSerializer
|
||||||
from .serializers import UserSerializer, AuthSerializer
|
from .serializers import UserSerializer, AuthSerializer
|
||||||
|
from .exceptions import NotAuthorized, JWTExpired
|
||||||
# others
|
# others
|
||||||
import jwt
|
import jwt
|
||||||
import datetime
|
import datetime
|
||||||
|
@ -12,9 +13,9 @@ from decouple import config
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from django.core.exceptions import PermissionDenied
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
class ProjectViewSet(viewsets.ModelViewSet):
|
class ProjectViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Project.objects.all()
|
queryset = Project.objects.all()
|
||||||
serializer_class = ProjectSerializer
|
serializer_class = ProjectSerializer
|
||||||
|
@ -36,6 +37,7 @@ class UserViewSet(viewsets.ModelViewSet):
|
||||||
"""
|
"""
|
||||||
private_key = config('SECRET_JWT','palabrasecreta')
|
private_key = config('SECRET_JWT','palabrasecreta')
|
||||||
|
|
||||||
|
# @csrf_exempt
|
||||||
class AuthViewSet(viewsets.ViewSet):
|
class AuthViewSet(viewsets.ViewSet):
|
||||||
serializer_class = AuthSerializer
|
serializer_class = AuthSerializer
|
||||||
|
|
||||||
|
@ -47,30 +49,35 @@ class AuthViewSet(viewsets.ViewSet):
|
||||||
password = request.data.get('password')
|
password = request.data.get('password')
|
||||||
|
|
||||||
user = User.objects.filter(username = username).first()
|
user = User.objects.filter(username = username).first()
|
||||||
|
if not user:
|
||||||
|
raise NotAuthorized
|
||||||
is_correct = user.check_password(password)
|
is_correct = user.check_password(password)
|
||||||
if not is_correct:
|
if not is_correct:
|
||||||
raise PermissionDenied
|
raise NotAuthorized
|
||||||
|
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
payload = {
|
payload = {
|
||||||
'exp': now + datetime.timedelta(hours=1),
|
'exp': now + datetime.timedelta(minutes=1),
|
||||||
'user_id': user.id
|
'user_id': user.id
|
||||||
}
|
}
|
||||||
token = jwt.encode(payload, private_key, algorithm="HS256")
|
token = jwt.encode(payload, private_key, algorithm="HS256")
|
||||||
response = Response({ 'token': token })
|
response = Response({ 'token': token })
|
||||||
response.set_cookie('token', token)
|
# response.set_cookie('token', token)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@action(detail=False, methods=['get'])
|
@action(detail=False, methods=['get'])
|
||||||
def info(self, request, pk=None):
|
def info(self, request, pk=None):
|
||||||
token = request.COOKIES.get('token')
|
token = request.COOKIES.get('token')
|
||||||
if not token:
|
if not token:
|
||||||
raise PermissionDenied
|
return Response(data = None, content_type = 'application/json')
|
||||||
decode = jwt.decode(token, private_key, algorithms= ["HS256"])
|
try:
|
||||||
|
decode = jwt.decode(token, private_key, algorithms= ["HS256"])
|
||||||
|
except jwt.ExpiredSignature:
|
||||||
|
raise JWTExpired
|
||||||
|
|
||||||
user = User.objects.filter(id = decode.get('user_id')).values().first()
|
user = User.objects.filter(id = decode.get('user_id')).values().first()
|
||||||
if (user == None):
|
if (not user):
|
||||||
raise PermissionDenied
|
raise NotAuthorized
|
||||||
|
|
||||||
return Response({
|
return Response({
|
||||||
'id': user.get('id'),
|
'id': user.get('id'),
|
||||||
|
@ -87,8 +94,8 @@ class AuthViewSet(viewsets.ViewSet):
|
||||||
decode = jwt.decode(token, private_key, algorithms= ["HS256"])
|
decode = jwt.decode(token, private_key, algorithms= ["HS256"])
|
||||||
|
|
||||||
user = User.objects.filter(id = decode.get('user_id')).values().first()
|
user = User.objects.filter(id = decode.get('user_id')).values().first()
|
||||||
if (user == None):
|
if (not user):
|
||||||
raise PermissionDenied
|
raise NotAuthorized
|
||||||
|
|
||||||
return Response({
|
return Response({
|
||||||
'id': user.get('id'),
|
'id': user.get('id'),
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
.navbar ul{list-style-type:none;margin:0;padding:0;overflow:hidden;background-color:#333}.navbar li{float:left}.navbar li a{display:block;color:#fff;text-align:center;padding:14px 16px;text-decoration:none}.navbar li a:hover{background-color:#111}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Capacitacion de svelte</title>
|
||||||
|
<script type="module" crossorigin src="/assets/index-0c98eb67.js"></script>
|
||||||
|
<link rel="stylesheet" href="/assets/index-782abf0e.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -40,12 +40,14 @@ INSTALLED_APPS = [
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'coreapi',
|
'coreapi',
|
||||||
|
'corsheaders',
|
||||||
'api'
|
'api'
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'corsheaders.middleware.CorsMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
@ -58,7 +60,7 @@ ROOT_URLCONF = 'project.urls'
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
'DIRS': [],
|
'DIRS': [ BASE_DIR / 'dist/' ],
|
||||||
'APP_DIRS': True,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
|
@ -126,7 +128,11 @@ USE_TZ = True
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||||
|
|
||||||
STATIC_URL = 'static/'
|
STATIC_URL = 'assets/'
|
||||||
|
|
||||||
|
STATICFILES_DIRS = [
|
||||||
|
BASE_DIR / 'dist/assets',
|
||||||
|
]
|
||||||
|
|
||||||
# Default primary key field type
|
# Default primary key field type
|
||||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
||||||
|
@ -136,4 +142,9 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
|
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CORS_ALLOW_CREDENTIALS = True
|
||||||
|
CORS_ALLOWED_ORIGINS = [
|
||||||
|
"http://localhost:3000",
|
||||||
|
]
|
|
@ -14,12 +14,26 @@ Including another URLconf
|
||||||
1. Import the include() function: from django.urls import include, path
|
1. Import the include() function: from django.urls import include, path
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
|
from django.http import HttpResponse
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.documentation import include_docs_urls
|
from rest_framework.documentation import include_docs_urls
|
||||||
|
|
||||||
|
from django.template.loader import get_template
|
||||||
|
from django.conf import settings
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
|
|
||||||
|
def frontend(request):
|
||||||
|
plantilla = get_template('index.html')
|
||||||
|
documento = plantilla.render()
|
||||||
|
return HttpResponse(documento)
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('', frontend),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('api/', include('api.urls')),
|
path('api/', include('api.urls')),
|
||||||
path('docs/', include_docs_urls(title = 'API Documentation'))
|
path('docs/', include_docs_urls(title = 'API Documentation'))
|
||||||
]
|
] + static(settings.STATIC_URL, document_root=settings.STATICFILES_DIRS[0])
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* **Django**: framework django
|
* **Django**: framework django
|
||||||
* **psycopg2-binary**: permite uso de base datos postgres
|
* **psycopg2-binary**: permite uso de base datos postgres
|
||||||
* **djangorestframework**: permite crear rest api json
|
* **djangorestframework**: permite crear rest api json
|
||||||
|
* **django-cors-headers**: requerido para desarrollo de frontend, permite acceso desde una dominio distinto al backend
|
||||||
* **coreapi**: genera documentación de rest api
|
* **coreapi**: genera documentación de rest api
|
||||||
* **python-decouple**: lee archivo .env para variables de ambiente
|
* **python-decouple**: lee archivo .env para variables de ambiente
|
||||||
* **PyJWT**: permite generar json-web-token
|
* **PyJWT**: permite generar json-web-token
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
Django
|
Django
|
||||||
psycopg2-binary
|
psycopg2-binary
|
||||||
djangorestframework
|
djangorestframework
|
||||||
|
django-cors-headers
|
||||||
coreapi
|
coreapi
|
||||||
python-decouple
|
python-decouple
|
||||||
PyJWT
|
PyJWT
|
Loading…
Reference in New Issue