One place for hosting & domains

      aplicación

      Cómo implementar una aplicación Django escalable y segura con Kubernetes


      Introducción

      En este tutorial, implementará una aplicación de encuestas de Django en contenedor en un clúster de Kubernetes.

      Django es un poderoso framework web que puede ayudarle a poner en marcha rápidamente su aplicación o sitio web con Python. Incluye varias características convenientes como un mapeo objeto-relacional, la autenticación de usuarios y una interfaz administrativa personalizable para su aplicación. También incluye un marco de almacenamiento en caché y fomenta el diseño limpio de aplicaciones a través de su Despachador URL y sistema de Plantillas

      En Cómo crear una aplicación Django y Gunicorn con Docker, la aplicación de encuestas del Tutorial de Django fue modificada de acuerdo con la metodología de Twelve-Factor para crear aplicaciones web escalables y nativas en la nube. Esta configuración en contenedores se escaló y protegió con un proxy inverso Nginx y certificados TLS proporcionados por Let’s Encrypt en Cómo escalar y proteger una aplicación de Django con Docker, Nginx y Let’s Encrypt. En este tutorial final de la serie “De contenedores a Kubernetes con Django”, la aplicación de encuestas de Django modernizada se implementará en un clúster de Kubernetes.

      Kubernetes es un potente orquestador de contenedores de código abierto que automatiza la implementación, el escalamiento y la administración de aplicaciones en contenedores. Los objetos de Kubernetes, como ConfigMaps y Secrets, permiten centralizar y desvincular la configuración de los contenedores, mientras que los controladores como las implementaciones reinician automáticamente los contenedores fallidos y habilitar el escalamiento rápido de las réplicas de contenedores. El cifrado TLS se activa con un objeto Ingress y el controlador de Ingress de código abierto llamado ingress-nginx. El complemento cert-manager de Kubernetes renueva y emite certificados usando la autoridad de certificación de Let’s Encrypt gratuita.

      Requisitos previos

      Para seguir este tutorial, necesitará lo siguiente:

      • Un clúster de Kubernetes 1.15, o una versión posterior, con control de acceso basado en roles (RBCA) activado. Esta configuración usará un clúster de Kubernetes de DigitalOcean, pero puede crear un clúster usando otro método.
      • La herramienta de línea de comandos kubectl instalada en su equipo local y configurada para conectarse a su clúster. Puede leer más sobre la instalación de kubectl en la documentación oficial. Si está usando un clúster de Kubernetes de DigitalOcean, consulte Cómo conectarse a un clúster Kubernetes de DigitalOcean para aprender a conectarse a su clúster usando kubectl.
      • Un nombre de dominio registrado. Para este tutorial, se utilizará your_domain.com en todo momento. Puede obtener un ejemplar gratis en Freenom o utilizar el registrador de dominios que desee.
      • Un controlador de Ingress ingress-nginx y el administrador de certificados TLS cert-manager instalado en su clúster y configurado para emitir certificados TLS. Para aprender a instalar y configurar un Ingress con cert-manager, consulte Cómo configurar un Ingress de Nginx con Cert-Manager en Kubernetes de DigitalOcean.
      • Un registro DNS A con your_domain.com orientado a la dirección IP pública del equilibrador de cargas de Ingress. Si usa DigitalOcean para administrar los registros DNS de su dominio, consulte Cómo administrar registros DNS para aprender a crear registros A.
      • Un depósito de almacenamiento de objetos S3, como un Space de DigitalOcean, para almacenar los archivos estáticos de su proyecto de Django y un conjunto de claves de acceso para ese espacio. Para obtener información sobre cómo crear Spaces, consulte la documentación de Cómo crear Spaces. Para obtener información sobre cómo crear claves de acceso para Spaces, consulte Compartir el acceso a Spaces con claves de acceso. Con cambios menores, puede usar cualquier servicio de almacenamiento de objetos que admita el complemento django-storages
      • Una instancia de un servidor de PostgreSQL, una base de datos y un usuario para su aplicación de Django. Con cambios menores, puede usar cualquier base de datos que admita Django.
      • Un Docker Hub cuenta y repositorio público. Para obtener más información sobre cómo crearlos, consulte Repositorios de la documentación de Docker.
      • El motor Docker instalado en su máquina local. Consulte Cómo instalar y usar Docker en Ubuntu 18.04 para obtener más información.

      Una vez que haya configurado estos componentes, estará listo para comenzar con esta guía.

      Paso 1: Clonar y probar la aplicación

      En este paso, clonaremos el código de la aplicación de GitHub y configuraremos ajustes como las credenciales de la base de datos y las claves de almacenamiento de objetos.

      El código de la aplicación y Dockerfile se encuentran en la rama polls-docker del repositorio de GitHub de la aplicacipon Polls en el tutorial de Django. Este repositorio contiene el código para la aplicación Polls de muestra de la documentación de Django, que le enseña cómo crear una aplicación de encuestas desde cero.

      La rama polls-docker contiene una versión con Docker de esta aplicación Polls. Para obtener información sobre cómo se modificó la aplicación Polls para que funcionara de forma eficaz en un entorno de contenedores, consulte Cómo crear una aplicación de Django y Gunicorn con Docker.

      Comience usando git para clonar la rama polls-docker del repositorio de GitHub de la aplicación Polls del tutorial de Django en su máquina local:

      • git clone --single-branch --branch polls-docker https://github.com/do-community/django-polls.git

      Diríjase al directorio django-polls:

      Este directorio contiene el código de Python de la aplicación de Django, un Dockerfile que Docker utilizará para crear la imagen del contenedor, y un archivo env que contiene una lista de las variables de entorno que se pasarán al entorno de ejecución del contenedor. Inspeccione el Dockerfile:

      Output

      FROM python:3.7.4-alpine3.10 ADD django-polls/requirements.txt /app/requirements.txt RUN set -ex && apk add --no-cache --virtual .build-deps postgresql-dev build-base && python -m venv /env && /env/bin/pip install --upgrade pip && /env/bin/pip install --no-cache-dir -r /app/requirements.txt && runDeps="$(scanelf --needed --nobanner --recursive /env | awk '{ gsub(/,/, "nso:", $2); print "so:" $2 }' | sort -u | xargs -r apk info --installed | sort -u)" && apk add --virtual rundeps $runDeps && apk del .build-deps ADD django-polls /app WORKDIR /app ENV VIRTUAL_ENV /env ENV PATH /env/bin:$PATH EXPOSE 8000 CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "mysite.wsgi"]

      Este Dockerfile utiliza la imagen de Docker oficial de Python 3.7.4 como base e instala los requisitos del paquete de Python de Django y Gunicorn, tal como se define en el archivo django-polls/requirements.txt. A continuación, elimina algunos archivos de compilación innecesarios, copia el código de la aplicación en la imagen y establece el PATH de ejecución. Por último, declara que el puerto 8000 se utilizará para aceptar conexiones de contenedores entrantes y ejecuta gunicorn con 3 trabajadores, escuchando en el puerto 8000.

      Para obtener más información sobre cada uno de los pasos de este Dockerfile, consulte el Paso 6 de Cómo crear una aplicación de Django y Gunicorn con Docker.

      Ahora, compile la imagen con docker build:

      Nombramos la imagen polls con el indicador -t y pasamos el directorio actual como contexto de compilación, el conjunto de archivos a los que se debe hacer referencia al construir la imagen.

      Una vez que Docker haya compilado y etiquetado la imagen, enumere las imágenes disponibles utilizando docker images:

      Debería ver la imagen polls enumerada:

      OutputREPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
      polls               latest              80ec4f33aae1        2 weeks ago         197MB
      python              3.7.4-alpine3.10    f309434dea3a        8 months ago        98.7MB
      

      Antes de ejecutar el contenedor de Django, debemos configurar su entorno de ejecución utilizando el archivo env presente en el directorio actual. Este archivo se pasará al comando docker run que se utiliza para ejecutar el contenedor y Docker insertará las variables de entorno configuradas en el entorno en ejecución del contenedor.

      Abra el archivo env con nano o su editor favorito:

      django-polls/env

      DJANGO_SECRET_KEY=
      DEBUG=True
      DJANGO_ALLOWED_HOSTS=
      DATABASE_ENGINE=postgresql_psycopg2
      DATABASE_NAME=polls
      DATABASE_USERNAME=
      DATABASE_PASSWORD=
      DATABASE_HOST=
      DATABASE_PORT=
      STATIC_ACCESS_KEY_ID=
      STATIC_SECRET_KEY=
      STATIC_BUCKET_NAME=
      STATIC_ENDPOINT_URL=
      DJANGO_LOGLEVEL=info
      

      Complete los valores que faltan para las siguientes claves:

      • DJANGO_SECRET_KEY: establézcala en un valor único e impredecible, como se detalla en la documentación de Django. Se proporciona un método para generar esta clave en la sección Ajustar la configuración de la aplicación del tutorial Aplicaciones escalables de Django.
      • DJANGO_ALLOWED_HOSTS: esta variable asegura la aplicación y evita ataques a través del encabezado de host HTTP. Para propósitos de prueba, establézcala en *, un comodín que coincidirá con todos los hosts. En producción, debe establecerlo en your_domain.com. Para obtener más información sobre esta configuración de Django, consulte la sección Configuración principal en la documentación de Django.
      • DATABASE_USERNAME: establézcalo en el usuario de la base de datos de PostgreSQL creado en los pasos de requisitos previos.
      • DATABASE_NAME: establézcalo en polls o el nombre de la base de datos de PostgreSQL creado en los pasos de requisitos previos.
      • DATABASE_PASSWORD: establézcala en la contraseña de la base de datos de PostgreSQL creada en los pasos de requisitos previos.
      • DATABASE_HOST: establézcalo en el nombre de host de su base de datos.
      • DATABASE_PORT: establézcalo en el puerto de su base de datos.
      • STATIC_ACCESS_KEY_ID: establézcala en la clave de acceso de Space o en el almacenamiento de objetos.
      • STATIC_SECRET_KEY: establézcala en Secret de la clave de acceso de su Space o en el almacenamiento de objetos.
      • STATIC_BUCKET_NAME: establézcalo en el nombre de su Space o en el depósito de almacenamiento de objetos.
      • STATIC_ENDPOINT_URL: establézcala en la URL de extremo de Spaces o del almacenamiento del objeto que corresponda, por ejemplo, https://your_space_name.nyc3.digitaloceanspaces.com, si su Space está ubicado en la región nyc3.

      Una vez que haya finalizado la edición, guarde y cierre el archivo.

      En el siguiente paso, ejecutaremos el contenedor configurado a nivel local y crearemos el esquema de la base de datos. También cargaremos activos estáticos como hojas de estilos e imágenes al almacenamiento de objetos.

      Paso 2: Crear el esquema de la base de datos y cargar activos en el almacenamiento de objetos

      Con el contenedor creado y configurado, utilizaremos docker run para anular el CMD establecido en Dockerfile y crear el esquema de la base de datos utilizando los comandos manage.py makemigrations y manage.py migrate:

      • docker run --env-file env polls sh -c "python manage.py makemigrations && python manage.py migrate"

      Ejecutamos la imagen del contenedor polls:latest, pasamos el archivo de variables de entorno que acabamos de modificar y anulamos el comando de Dockerfile con sh -c "python manage.py makemigrations && python manage.py migrate", lo que creará el esquema de la base de datos definido mediante el código de la aplicación.

      Si lo está ejecutando por primera vez, debería ver lo siguiente:

      Output

      No changes detected Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying polls.0001_initial... OK Applying sessions.0001_initial... OK

      Esto indica que el esquema de la base de datos se ha creado correctamente.

      Si no está ejecutando migrate por primera vez, Django realizará un no-op a menos que el esquema de la base de datos haya cambiado.

      A continuación, ejecutaremos otra instancia del contenedor de la aplicación y utilizaremos una shell interactiva en su interior para crear un usuario administrativo para el proyecto de Django.

      • docker run -i -t --env-file env polls sh

      Esto le proporcionará una línea de comandos de shell dentro del contenedor en ejecución que puede usar para crear el usuario de Django:

      • python manage.py createsuperuser

      Ingrese un nombre de usuario, una dirección de correo electrónico y una contraseña para su usuario y, una vez que haya creado el usuario, presione CTRL+D para salir del contenedor y cerrarlo.

      Por último, generaremos los archivos estáticos de la aplicación y los subiremos al Space de DigitalOcean utilizando collectstatic. Tenga en cuenta que esta operación puede tardar un poco en completarse.

      • docker run --env-file env polls sh -c "python manage.py collectstatic --noinput"

      Una vez que estos archivos se hayan generado y cargado, obtendrá el siguiente resultado.

      Output

      121 static files copied.

      Ahora, podemos ejecutar la aplicación:

      • docker run --env-file env -p 80:8000 polls

      Output

      [2019-10-17 21:23:36 +0000] [1] [INFO] Starting gunicorn 19.9.0 [2019-10-17 21:23:36 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1) [2019-10-17 21:23:36 +0000] [1] [INFO] Using worker: sync [2019-10-17 21:23:36 +0000] [7] [INFO] Booting worker with pid: 7 [2019-10-17 21:23:36 +0000] [8] [INFO] Booting worker with pid: 8 [2019-10-17 21:23:36 +0000] [9] [INFO] Booting worker with pid: 9

      Aquí, ejecutamos el comando predeterminado definido en el Dockerfile, gunicorn --bind :8000 --workers 3 mysite.wsgi:application y exponemos el puerto del contenedor 8000 para que el puerto 80 en su máquina local se asigne al puerto 8000 del contenedor polls.

      Ahora, debería poder navegar a la aplicación polls desde su navegador web al http://localhost en la barra de direcciones URL. Dado que no hay una ruta definida para la ruta / , es probable que reciba un error de 404 Page Not Found (Página no encontrada), lo que es de esperar.

      Diríjase a http://localhost/polls para ver la interfaz de la aplicación Polls:

      Interfaz de la aplicación Polls

      Para ver la interfaz administrativa, visite http://localhost/admin. Debería ver la ventana de autenticación de administración de la aplicación Polls:

      Página de autenticación de administración de Polls

      Ingrese el nombre de usuario administrativo y la contraseña que creó con el comando createsuperuser.

      Después de la autenticación, podrá acceder a la interfaz administrativa de la aplicación Polls:

      Interfaz principal de administración de Polls

      Tenga en cuenta que los que los recursos estáticos de las aplicaciones admin y polls se entregan directamente desde el almacenamiento de objetos. Para confirmar esto, consulte Prueba de la entrega de archivos estáticos de Spaces.

      Cuando haya terminado de explorar, presione CTRL+C en la ventana de terminal que está ejecutando el contenedor de Docker para cerrar el contenedor.

      Con la imagen de Docker de la aplicación de Django probada, los activos estáticos que se cargan en el almacenamiento de objetos y el esquema de la base de datos configurado y listo para ser utilizado en su aplicación, estará listo para subir la imagen de su aplicación de Django a un registro de imágenes como Docker Hub.

      Paso 3: Introducir la imagen de la aplicación de Django en Docker Hub

      Para implementar su aplicación en Kubernetes, la imagen de su aplicación debe cargarse en un registro como Docker Hub. Kubernetes extraerá la imagen de la aplicación de su repositorio y luego la implementará en su clúster.

      Puede usar un registro de Docker privado, como DigitalOcean Container Registry, actualmente gratuito en Early Access o un registro de Docker público como Docker Hub. Docker Hub también le permite crear repositorios de Docker privados. Un repositorio público permite a cualquiera ver y extraer las imágenes del contenedor, mientras que un repositorio privado permite restringir el acceso a usted y a los miembros de su equipo.

      En este tutorial, introduciremos la imagen de Django en el repositorio de Docker Hub público creado en los requisitos previos. También puede introducir su imagen en un repositorio privado, pero extraer imágenes de un repositorio privado no es el tema de este artículo. Para obtener más información sobre la autenticación de Kubernetes con Docker Hub y la extracción de imágenes privadas, consulte Extraer una imagen de un registro privado en la documentación de Kubernetes.

      Comience iniciando sesión en Docker Hub en su máquina local:

      Output

      Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username:

      Ingrese su nombre de usuario y contraseña de Docker Hub para iniciar sesión.

      La imagen de Django actualmente tiene la etiqueta polls:latest. Para introducirla en su repositorio de Docker Hub, vuelva a etiquetar la imagen con su nombre de usuario de Docker Hub y nombre de repositorio:

      • docker tag polls:latest your_dockerhub_username/your_dockerhub_repo_name:latest

      Introduzca la imagen en el repositorio:

      • docker push sammy/sammy-django:latest

      En este tutorial, el nombre de usuario de Docker Hub es sammy y el nombre de repositorio es sammy-django. Debe sustituir estos valores por su propio nombre de usuario y nombre de repositorio de Docker Hub.

      Verá un resultado que se actualiza a medida que las capas de imágenes se insertan en Docker Hub.

      Ahora que su imagen está disponible para Kubernetes en Docker Hub, puede comenzar a implementarla en su clúster.

      Paso 4: Configurar ConfigMap

      Cuando ejecutamos el contenedor de Django a nivel local, pasamos el archivo env a docker run para insertar variables de configuración en el entorno de tiempo de ejecución. En Kubernetes, las variables de configuración pueden insertarse usando ConfigMaps y Secrets.

      ConfigMaps debe usarse para almacenar información de configuración no confidencial, la configuración de la aplicación, mientras que Secrets debe usarse para información confidencial, como claves de API y credenciales de la base de datos. Ambos se insertan en contenedores de forma similar, pero Secrets tienen funciones de control de acceso y seguridad adicionales como encriptación en reposo. Secrets también almacenan datos en base64, mientras que ConfigMaps almacenan datos en texto simple.

      Para comenzar, cree un directorio llamado yaml en el que almacenaremos nuestros manifiestos de Kubernetes. Diríjase al directorio.

      Abra un archivo llamado polls-configmap.yaml en nano o su editor de texto preferido:

      • nano polls-configmap.yaml

      Pegue el siguiente manifiesto de ConfigMap:

      polls-configmap.yaml

      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: polls-config
      data:
        DJANGO_ALLOWED_HOSTS: "*"
        STATIC_ENDPOINT_URL: "https://your_space_name.space_region.digitaloceanspaces.com"
        STATIC_BUCKET_NAME: "your_space_name"
        DJANGO_LOGLEVEL: "info"
        DEBUG: "True"
        DATABASE_ENGINE: "postgresql_psycopg2"
      

      Extrajimos la configuración no sensible del archivo env modificado en el Paso 1 y la pegamos en un manifiesto de ConfigMap. El objeto ConfigMap se llama polls-config. Copie los mismos valores que ingresó en el archivo env en el paso anterior.

      Para propósitos de prueba, establezca DJANGO_ALLOWED_HOSTS como * para desactivar el filtrado del encabezado de host. En un entorno de producción, debe establecerlo en el dominio de su aplicación.

      Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

      Cree ConfigMap en su clúster usando kubectl apply:

      • kubectl apply -f polls-configmap.yaml

      Output

      configmap/polls-config created

      Después de crear ConfigMap, crearemos el Secret que usó nuestra aplicación en el siguiente paso.

      Paso 5: Configurar Secret

      Los valores de Secret deben estar codificados en base64, lo que significa que crear objetos de Secret en su clúster es ligeramente más complicado que crear ConfigMaps. Puede repetir el proceso del paso anterior, codificando de forma manual los valores de Secret de base64 y pegándolos en un archivo de manifiesto. También puede crearlos usando un archivo de variable de entorno, kubectl create y el indicador --from-env-file, que realizaremos en este paso.

      Una vez más, usaremos el archivo env del Paso 1, eliminando las variables insertadas en ConfigMap. Cree una copia del archivo env llamado polls-secrets en el directorio yaml:

      • cp ../env ./polls-secrets

      Edite el archivo en el editor de su preferencia:

      polls-secrets

      DJANGO_SECRET_KEY=
      DEBUG=True
      DJANGO_ALLOWED_HOSTS=
      DATABASE_ENGINE=postgresql_psycopg2
      DATABASE_NAME=polls
      DATABASE_USERNAME=
      DATABASE_PASSWORD=
      DATABASE_HOST=
      DATABASE_PORT=
      STATIC_ACCESS_KEY_ID=
      STATIC_SECRET_KEY=
      STATIC_BUCKET_NAME=
      STATIC_ENDPOINT_URL=
      DJANGO_LOGLEVEL=info
      

      Elimine todas las variables insertadas en el manifiesto de ConfigMap. Cuando haya terminado, debe verse así:

      polls-secrets

      DJANGO_SECRET_KEY=your_secret_key
      DATABASE_NAME=polls
      DATABASE_USERNAME=your_django_db_user
      DATABASE_PASSWORD=your_django_db_user_password
      DATABASE_HOST=your_db_host
      DATABASE_PORT=your_db_port
      STATIC_ACCESS_KEY_ID=your_space_access_key
      STATIC_SECRET_KEY=your_space_access_key_secret
      

      Asegúrese de usar los mismos valores que se utilizan en el Paso 1. Cuando haya terminado, guarde y cierre el archivo.

      Cree el Secret en su clúster usando kubectl create secret:

      • kubectl create secret generic polls-secret --from-env-file=poll-secrets

      Output

      secret/polls-secret created

      Aquí creamos un objeto Secret llamado polls-secret y pasamos el archivo de secrets que acabamos de crear.

      Puede inspeccionar el Secret usando kubectl describe:

      • kubectl describe secret polls-secret

      Output

      Name: polls-secret Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== DATABASE_PASSWORD: 8 bytes DATABASE_PORT: 5 bytes DATABASE_USERNAME: 5 bytes DJANGO_SECRET_KEY: 14 bytes STATIC_ACCESS_KEY_ID: 20 bytes STATIC_SECRET_KEY: 43 bytes DATABASE_HOST: 47 bytes DATABASE_NAME: 5 bytes

      En este punto, almacenó la configuración de su aplicación en el clúster de Kubernetes usando los tipos de objeto Secret y ConfigMap. Ahora estamos listos para implementar la aplicación en el clúster.

      Paso 6: Implementar la aplicación de Django usando una implementación

      En este paso, creará una implementación para su aplicación de Django. Una implementación de Kubernetes es un controlador que puede usarse para administrar aplicaciones sin estado en su clúster. Un controlador es un bucle de control que regula las cargas de trabajo aumentándolas o reduciéndolas. Los controladores también reinician y eliminan los contenedores fallidos.

      Las implementaciones controlan uno o más Pods, la unidad implementable más pequeña de un clúster de Kubernetes. Los Pods están compuestos por uno o más contenedores. Para obtener más información sobre los diferentes tipos de cargas de trabajo que puede iniciar, consulte Introducción a Kubernetes.

      Empiece por abrir un archivo llamado polls-deployment.yaml en su editor favorito:

      • nano polls-deployment.yaml

      Pegue el siguiente manifiesto de implementación:

      polls-deployment.yaml

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: polls-app
        labels:
          app: polls
      spec:
          replicas: 2
        selector:
          matchLabels:
            app: polls
        template:
          metadata:
            labels:
              app: polls
          spec:
            containers:
              - image: your_dockerhub_username/app_repo_name:latest
                name: polls
                envFrom:
                - secretRef:
                    name: polls-secret
                - configMapRef:
                    name: polls-config
                ports:
                  - containerPort: 8000
                    name: gunicorn
      

      Complete el nombre de la imagen del contenedor correspondiente, haciendo referencia a la imagen de Django Polls que agregó a Docker Hub en el Paso 2.

      Aquí definimos una implementación de Kubernetes llamada polls-app y la etiquetamos con el par clave-valor app: polls. Especificamos que queremos ejecutar dos réplicas del Pod especificado debajo del campo template.

      Usando envFrom con secretRef y configMapRef, especificamos que todos los datos del Secret polls-secret y el ConfigMap polls-config deben insertarse en los contenedores como variables de entorno. Las claves ConfigMap y Secret se convierten en los nombres de las variables de entorno.

      Por último, exponemos el containerPort 8000 y lo nombramos gunicorn.

      Para obtener más información sobre la configuración de las implementaciones de Kubernetes, consulte Implementaciones en la documentación de Kubernetes.

      Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

      Cree la implementación en su clúster usando kubectl apply -f:

      • kubectl apply -f polls-deployment.yaml
      • deployment.apps/polls-app created

      Compruebe que la implementación se implementó correctamente usando kubectl get:

      • kubectl get deploy polls-app

      Output

      NAME READY UP-TO-DATE AVAILABLE AGE polls-app 2/2 2 2 6m38s

      Si encuentra un error o considera que algo no está funcionando, puede usar kubectl describe para inspeccionar la implementación fallida:

      Puede inspeccionar los dos Pods usando kubectl get pod:

      Output

      NAME READY STATUS RESTARTS AGE polls-app-847f8ccbf4-2stf7 1/1 Running 0 6m42s polls-app-847f8ccbf4-tqpwm 1/1 Running 0 6m57s

      Ahora hay dos réplicas de su aplicación de Django ejecutándose en el clúster. Para acceder a la aplicación, es necesario crear un Service de Kubernetes, lo cual es lo que haremos a continuación.

      En este paso, creará un Service para su aplicación de Django. Un Service de Kubernetes es una abstracción que le permite exponer un conjunto de Pods en ejecución como servicio de red. Mediante un Service, puede crear un extremo estable para su aplicación que no cambia a medida que los Pods mueren y se vuelvan a crear.

      Existen varios tipos de Service, incluidos ClusterIP Services, que exponen el servicio en un IP interno del clúster, NodePort Services que exponen el servicio en cada Nodo en un puerto estático llamado NodePort y LoadBalancer Services que proporcionan un equilibrador de carga en la nube para dirigir el tráfico externo a los Pods de su clúster (a través de NodePorts, que crea automáticamente). Para obtener más información sobre esos servicios, consulte el artículo Service en la documentación de Kubernetes.

      En nuestra configuración final, usaremos un Service ClusterIP que se expone usando un Ingress y el controlador de Ingress configurado en los requisitos previos de esta guía. Por ahora, para comprobar que todo funciona correctamente, crearemos un servicio de NodePort temporal para acceder a la aplicación de Django.

      Comience creando un archivo llamado polls-svc.yaml usando el editor de su preferencia:

      Pegue el siguiente manifiesto de Service:

      polls-svc.yaml

      apiVersion: v1
      kind: Service
      metadata:
        name: polls
        labels:
          app: polls
      spec:
        type: NodePort
        selector:
          app: polls
        ports:
          - port: 8000
            targetPort: 8000
      

      Aquí creamos un Service NodePort llamado polls y le asignamos la etiqueta app: polls. A continuación, seleccionamos los Pods backend con la etiqueta app: polls y orientamos sus puertos 8000.

      Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

      Implemente el Service usando kubectl apply:

      • kubectl apply -f polls-svc.yaml

      Output

      service/polls created

      Confirme que su Service se creó usando kubectl get svc:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE polls NodePort 10.245.197.189 <none> 8000:32654/TCP 59s

      Este resultado muestra la IP y NodePort internos del clúster de Service (32654). Para conectarse al servicio, se necesitan las direcciones IP externas de los nodos del clúster:

      Output

      NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME pool-7no0qd9e0-364fd Ready <none> 27h v1.18.8 10.118.0.5 203.0.113.1 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9 pool-7no0qd9e0-364fi Ready <none> 27h v1.18.8 10.118.0.4 203.0.113.2 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9 pool-7no0qd9e0-364fv Ready <none> 27h v1.18.8 10.118.0.3 203.0.113.3 Debian GNU/Linux 10 (buster) 4.19.0-10-cloud-amd64 docker://18.9.9

      En su navegador web, visite su aplicación Polls usando la dirección IP externa de cualquier nodo y el NodePort. Dado el resultado anterior, la URL de la aplicación sería la siguiente: http://203.0.113.1:32654/polls.

      Debería poder ver la misma interfaz de la aplicación Polls a la que accedió a nivel local en el Paso 1:

      Interfaz de la aplicación Polls

      Puede repetir la misma prueba usando la ruta /admin: http://203.0.113.1:32654/admin. Debería ver la misma interfaz administrativa que antes:

      Página de autenticación de administración de Polls

      En esta etapa, ya implementó dos réplicas del contenedor de la aplicación Polls de Django usando una implementación. También creó un extremo de red estable para estas dos réplicas e hizo que se pueda acceder a ellas externamente usando un servicio de NodePort

      El paso final de este tutorial es proteger el tráfico externo a su aplicación usando HTTPS. Para ello, usaremos el controlador de Ingress-nginx instalado en los requisitos previos y crearemos un objeto de Ingress para dirigir el tráfico externo al servicio de Kubernetes de polls.

      Paso 8: Configurar HTTPS usando el Ingress y cert-manager de Nginx

      Los Ingress de Kubernetes le permiten dirigir de manera flexible el tráfico del exterior de su clúster de Kubernetes a servicios dentro de su clúster. Esto se realiza usando objetos de Ingress, que definen reglas para dirigir el tráfico HTTP y HTTPS a servicios de Kubernetes, y controladores de Ingress, que implementan las reglas equilibrando la carga de tráfico y dirigiéndola a los servicios de backend correspondientes.

      En los requisitos previos, instaló el controlador de Ingress-nginx y el complemento para automatizar certificados TLS cert-manager. También ha configurado el ClusterIssuers de ensayo y producción de su dominio usando la autoridad de certificación Let’s Encrypt, y ha creado un Ingress para probar la emisión de certificados y el cifrado TLS en dos servicios de backend ficticios. Antes de continuar con este paso, debe eliminar el Ingress echo-ingress creado en el tutorial de requisitos previos:

      • kubectl delete ingress echo-ingress

      Si desea, también puede eliminar los servicios y las implementaciones ficticios usando kubectl delete svc y kubectl delete deploy, pero no es necesario que lo haga para completar este tutorial.

      También debería haber creado un registro DNS A con your_domain.com orientado a la dirección IP pública del equilibrador de cargas de Ingress. Si usa un equilibrador de carga de DigitalOcean, puede encontrar esta dirección IP en la sección Equilibradores de carga del panel de control. Si también usa DigitalOcean para administrar los registros DNS de su dominio, consulte Cómo administrar registros DNS para aprender a crear registros A.

      Si usa Kubernetes de DigitalOcean, también asegúrese de implementar la solución descrita en el Paso 5 de Cómo configurar un Ingress de Nginx con Cert-Manager en Kubernetes de DigitalOcean.

      Una vez que tenga un registro A que apunte al equilibrador de carga del controlador de Ingress, puede crear un Ingress para your_domain.com y el servicio polls.

      Abra un archivo llamado polls-ingress.yaml usando el editor de su preferencia:

      Pegue el siguiente manifiesto de Ingress:

      [polls-ingress.yaml]
      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: polls-ingress
        annotations:
          kubernetes.io/ingress.class: "nginx"
          cert-manager.io/cluster-issuer: "letsencrypt-staging"
      spec:
        tls:
        - hosts:
          - your_domain.com
          secretName: polls-tls
        rules:
        - host: your_domain.com
          http:
            paths:
            - backend:
                serviceName: polls
                servicePort: 8000
      

      Creamos un objeto de Ingress llamado polls-ingress y lo anotamos para indicarle al plano de control que utilice el controlador de Ingress-nginx y el ClusterIssuer de ensayo. También habilitamos TLS para your_domain.com y almacenamos el certificado y la clave privada en un secret llamado polls-tls. Por último, definimos una regla para dirigir el tráfico del host your_domain.com al servicio polls del puerto 8000.

      Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

      Cree el Ingress en su clúster usando kubectl apply:

      • kubectl apply -f polls-ingress.yaml

      Output

      ingress.networking.k8s.io/polls-ingress created

      Puede usar kubectl describe para rastrear el estado del Ingress que acaba de crear:

      • kubectl describe ingress polls-ingress

      Output

      Name: polls-ingress Namespace: default Address: workaround.your_domain.com Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) TLS: polls-tls terminates your_domain.com Rules: Host Path Backends ---- ---- -------- your_domain.com polls:8000 (10.244.0.207:8000,10.244.0.53:8000) Annotations: cert-manager.io/cluster-issuer: letsencrypt-staging kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 51s nginx-ingress-controller Ingress default/polls-ingress Normal CreateCertificate 51s cert-manager Successfully created Certificate "polls-tls" Normal UPDATE 25s nginx-ingress-controller Ingress default/polls-ingress

      También puede ejecutar un describe en el certificado polls-tls para confirmar una vez más que se creó de manera correcta:

      • kubectl describe certificate polls-tls

      Output

      . . . Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Issuing 3m33s cert-manager Issuing certificate as Secret does not exist Normal Generated 3m32s cert-manager Stored new private key in temporary Secret resource "polls-tls-v9lv9" Normal Requested 3m32s cert-manager Created new CertificateRequest resource "polls-tls-drx9c" Normal Issuing 2m58s cert-manager The certificate has been successfully issued

      Esto confirma que el certificado TLS ha sido emitido con éxito y que el cifrado HTTPS ahora está activo para your_domain.com.

      Dado que usamos el ClusterIssuer de ensayo, la mayoría de los navegadores de Internet no confiarán en el certificado Let’s Encrypt que emitió. Por lo tanto, dirigirse a your_domain.com lo llevará a una página de error.

      Para enviar una solicitud de prueba, usaremos wget desde la línea de comandos:

      • wget -O - http://your_domain.com/polls

      Output

      . . . ERROR: cannot verify your_domain.com's certificate, issued by ‘CN=Fake LE Intermediate X1’: Unable to locally verify the issuer's authority. To connect to your_domain.com insecurely, use `--no-check-certificate'.

      Usaremos el indicador --no-check-certificate sugerido para omitir la validación del certificado:

      • wget --no-check-certificate -q -O - http://your_domain.com/polls

      Output

      <link rel="stylesheet" type="text/css" href="https://your_space.nyc3.digitaloceanspaces.com/django-polls/static/polls/style.css"> <p>No polls are available.</p>

      Este resultado muestra el HTML de la página de la interfaz /polls, lo que confirma también que la hoja de estilos se toma desde el almacenamiento de objetos.

      Ahora que probó con éxito la emisión de certificados usando el ClusterIssuer de ensayo, puede modificar el Ingress para usar el ClusterIssuer de producción.

      Abra polls-ingress.yaml para editar una vez más:

      Modifique la anotación cluster-issuer:

      [polls-ingress.yaml]
      apiVersion: networking.k8s.io/v1beta1
      kind: Ingress
      metadata:
        name: polls-ingress
        annotations:
          kubernetes.io/ingress.class: "nginx"
          cert-manager.io/cluster-issuer: "letsencrypt-prod"
      spec:
        tls:
        - hosts:
          - your_domain.com
          secretName: polls-tls
        rules:
        - host: your_domain.com
          http:
            paths:
            - backend:
                serviceName: polls
                servicePort: 8000
      

      Cuando termine, guarde y cierre el archivo. Actualice el Ingress usando kubectl apply:

      • kubectl apply -f polls-ingress.yaml

      Output

      ingress.networking.k8s.io/polls-ingress configured

      Puede usar kubectl describe certificate polls-tls y kubectl describe ingress polls-ingress para rastrear el estado de emisión del certificado:

      • kubectl describe ingress polls-ingress

      Output

      . . . Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 23m nginx-ingress-controller Ingress default/polls-ingress Normal CreateCertificate 23m cert-manager Successfully created Certificate "polls-tls" Normal UPDATE 76s (x2 over 22m) nginx-ingress-controller Ingress default/polls-ingress Normal UpdateCertificate 76s cert-manager Successfully updated Certificate "polls-tls"

      El resultado anterior confirma que el nuevo certificado de producción se emitió y almacenó con éxito en el Secret polls-tls.

      Diríjase a your_domain.com/polls en su navegador web para confirmar que el cifrado HTTPS está habilitado y que todo funciona según lo previsto. Debería ver la interfaz de la aplicación Polls:

      Interfaz de la aplicación Polls

      Verifique que el cifrado HTTPS está activo en su navegador web. Si usa Google Chrome, llegar a la página anterior sin errores confirma que todo funciona correctamente. Además, debe ver un candado en la barra de direcciones URL. Al hacer clic en el candado, se le permitirá inspeccionar los detalles del certificado Let’s Encrypt.

      Como tarea de limpieza final, puede cambiar opcionalmente el tipo de servicio polls de NodePort al tipo ClusterIP interno solamente.

      Modifique polls-svc.yaml usando su editor:

      Cambie el type de NodePort a ClusterIP:

      polls-svc.yaml

      apiVersion: v1
      kind: Service
      metadata:
        name: polls
        labels:
          app: polls
      spec:
        type: ClusterIP
        selector:
          app: polls
        ports:
          - port: 8000
            targetPort: 8000
      

      Cuando haya terminado de editar el archivo, guárdelo y ciérrelo.

      Implemente los cambios usando kubectl apply:

      • kubectl apply -f polls-svc.yaml --force

      Output

      service/polls configured

      Confirme que su Service se modificó usando kubectl get svc:

      Output

      NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE polls ClusterIP 10.245.203.186 <none> 8000/TCP 22s

      Este resultado muestra que el tipo de servicio es ahora ClusterIP. La única forma de acceder a él es a través de su dominio y del Ingress creado en este paso.

      Conclusión

      En este tutorial, implementó una aplicación de Django escalable y protegida con HTTPS en un clúster de Kubernetes. El contenido estático se toma directamente desde el almacenamiento de objetos y el número de Pods en ejecución puede aumentar o disminuir rápidamente usando el campo réplicas en el manifiesto de implementación polls-app.

      Si usa un Space de DigitalOcean, también puede habilitar la entrega de activos estáticos a través de una red de entrega de contenido y crear un subdominio personalizado para su Space. Consulte Habilitar CDN en Cómo configurar una aplicación de Django escalable con bases de datos y Spaces administrados por DigitalOcean para obtener más información.

      Para revisar el resto de la serie, visite nuestra página “De contenedores a Kubernetes con Django”.



      Source link

      Cómo habilitar la renderización del lado del servidor para una aplicación React


      Introducción

      La renderización del lado del servidor (SSR) es una técnica popular para renderizar una aplicación de una sola página (SPA) del lado del cliente en el servidor y enviar una página completamente renderizada al cliente. Esto permite que los componentes dinámicos se presenten como marcado HTML estático.

      Este enfoque puede ser útil para la optimización del motor de búsqueda (SEO) cuando la indexación no gestiona el JavaScript correctamente. También puede ser beneficioso en situaciones en las que descargar un paquete JavaScript grande sea difícil debido a una red lenta.

      En este tutorial, iniciará una aplicación React usando Create React App y luego modificará el proyecto para habilitar la renderización del lado del servidor.

      Al final de este tutorial, tendrá un proyecto funcional con una aplicación React del lado del cliente y una aplicación Express del lado del servidor.

      Nota: Alternativamente, Next.js ofrece un enfoque moderno para crear aplicaciones renderizadas estáticas y en servidor creadas con React.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      Este tutorial se verificó con Node v14.4.0 y npm v6.14.5.

      Paso 1: Crear la aplicación React y modificar el componente de la aplicación

      Primero, usamos npx para iniciar una nueva aplicación React usando la última versión de Create React App.

      Vamos a invocar nuestra aplicación my-ssr-app:

      • npx create-react-app@3.4.1 my-ssr-app

      A continuación, hacemos cd al nuevo directorio:

      cd my-ssr-app
      

      Finalmente, iniciamos nuestra nueva aplicación del lado del cliente para verificar la instalación:

      Debería ver una aplicación React de ejemplo en la ventana de su navegador.

      Ahora, vamos a crear un componente <Home>:

      A continuación, añada el siguiente código al archivo Home.js:

      src/Home.js

      import React from 'react';
      
      export default props => {
        return <h1>Hello {props.name}!</h1>;
      };
      

      Esto creará un encabezado <h1> con un mensaje "Hello" dirigido a un nombre.

      A continuación, vamos a renderizar <Home> en el componente <App>. Abra el archivo App.js:

      Luego, sustituya las líneas de código existentes con estas nuevas líneas de código:

      src/App.js

      import React from 'react';
      import Home from './Home';
      
      export default () => {
        return <Home name="Sammy" />;
      };
      

      Esto pasa un nombre al componente <Home> de forma que el mensaje que esperamos mostrar sea "Hello Sammy!".

      En el archivo index.js de nuestra aplicación, usaremos el método hydrate de ReactDOM en vez de render para indicar al renderizador DOM que estamos rehidratando la aplicación tras una renderización del lado del servidor.

      Vamos a abrir el archivo index.js:

      A continuación, sustituya el contenido del archivo index.js con el siguiente código:

      index.js

      import React from 'react';
      import ReactDOM from 'react-dom';
      import App from './App';
      
      ReactDOM.hydrate(<App />, document.getElementById('root'));
      

      Con esto concluye la configuración del lado del cliente y podemos pasar a configurar el lado del servidor.

      Paso 2: Crear un servidor Express y renderizar el componente de la aplicación

      Ahora que tenemos nuestra aplicación lista, vamos a configurar un servidor que enviará una versión renderizada. Usaremos Express para nuestro servidor. Vamos a añadirlo al proyecto introduciendo el siguiente comando en la ventana de su terminal:

      • npm install express@4.17.1

      O usando yarn:

      A continuación, cree un directorio server junto al directorio src de la aplicación:

      A continuación, cree un nuevo archivo index.js que contendrá el código del servidor Express:

      Añada las importaciones que necesitará y defina algunas constantes:

      server/index.js

      import path from 'path';
      import fs from 'fs';
      
      import React from 'react';
      import express from 'express';
      import ReactDOMServer from 'react-dom/server';
      
      import App from '../src/App';
      
      const PORT = process.env.PORT || 3006;
      const app = express();
      

      A continuación, añada el código del servidor con algunas funciones para la gestión de errores:

      server/index.js

      // ...
      
      app.get('/', (req, res) => {
        const app = ReactDOMServer.renderToString(<App />);
      
        const indexFile = path.resolve('./build/index.html');
        fs.readFile(indexFile, 'utf8', (err, data) => {
          if (err) {
            console.error('Something went wrong:', err);
            return res.status(500).send('Oops, better luck next time!');
          }
      
          return res.send(
            data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
          );
        });
      });
      
      app.use(express.static('./build'));
      
      app.listen(PORT, () => {
        console.log(`Server is listening on port ${PORT}`);
      });
      

      Como puede ver, podemos importar nuestro componente <App> desde la aplicación del cliente directamente desde el servidor.

      Aquí suceden tres cosas importantes:

      • Indicaremos a Express que sirva contenido desde el directorio build como archivos estáticos.
      • Usamos un método desde ReactDOMServer, renderToString para renderizar nuestra aplicación a una secuencia HTML estática.
      • A continuación, leemos el archivo estático index.html desde la aplicación creada del cliente, inyectamos el contenido estático de nuestra aplicación en el <div> con un id de "root" y enviamos eso como la respuesta a la solicitud.

      Paso 3: Configurar webpack, Babel y secuencias de comandos npm

      Para que funcione el código de nuestro servidor, necesitaremos empaquetarlo y compilarlo usando webpack y Babel. Para conseguir esto, vamos a añadir las dependencias dev al proyecto introduciendo el siguiente comando en la ventana de su terminal:

      • npm install webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --save-dev

      O usando yarn:

      • yarn add webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --dev

      Nota: Una versión anterior de este tutorial instaló babel-core, babel-preset-env, y babel-preset-react-app. Estos paquetes han sido archivados desde entonces, y se utilizan las versiones repo mono.

      A continuación, cree un archivo de configuración Babel:

      A continuación, añada los valores prestablecidos env y react-app:

      .babelrc.json

      {
        "presets": [
          "@babel/preset-env",
          "@babel/preset-react"
        ]
      }
      

      Nota: Una versión anterior de este tutorial usó un archivo .babelrc (no una extensión de archivo .json). Este era un archivo de configuración para Babel 6, pero ya no es así para Babel 7.

      Ahora, crearemos una configuración webpack para el servidor que utiliza Babel Loader para compilar el código. Comience creando el archivo:

      Luego, añada las siguientes configuraciones al archivo webpack.server.js:

      webpack.server.js

      const path = require('path');
      const nodeExternals = require('webpack-node-externals');
      
      module.exports = {
        entry: './server/index.js',
      
        target: 'node',
      
        externals: [nodeExternals()],
      
        output: {
          path: path.resolve('server-build'),
          filename: 'index.js'
        },
      
        module: {
          rules: [
            {
              test: /.js$/,
              use: 'babel-loader'
            }
          ]
        }
      };
      

      Con esta configuración, nuestro paquete compilado de servidor aparecerá a la carpeta server-build en un archivo llamado index.js.

      Observe que el uso target: 'node' y externals: [nodeExternals()] desde webpack-node-externals, que solo omitirá los archivos desde node_modules en el paquete; el servidor puede acceder a estos archivos directamente.

      Esto completa la instalación de la dependencia y la configuración de webpack y Babel.

      Ahora repasaremos package.json para ayudar secuencias de comandos npm de ayuda:

      Añadiremos secuencias de comandos dev:build-server, dev:start y dev al archivo package.json para crear y presentar nuestra aplicación SSR fácilmente:

      package.json

      "scripts": {
        "dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
        "dev:start": "nodemon ./server-build/index.js",
        "dev": "npm-run-all --parallel build dev:*",
        ...
      },
      

      Usamos nodemon para reiniciar el servidor cuando realicemos cambios. Y usamos npm-run-all para ejecutar varios comandos en paralelo.

      Vamos a instalar esos paquetes ahora introduciendo los siguientes comandos en la ventana de su terminal:

      • npm install nodemon@2.0.4 npm-run-all@4.1.5 --save-dev

      O usando yarn:

      • yarn add nodemon@2.0.4 npm-run-all@4.1.5 --dev

      Con esto, puede ejecutar lo siguiente para crear la aplicación del lado del cliente, empaquetar y compilar el código del servidor e iniciar el servidor en :3006:

      O usando yarn:

      La configuración webpack de nuestro servidor vigilará los cambios y nuestro servidor se reiniciará cuando haya cambios. Para la aplicación cliente, sin embargo, actualmente aún debemos crearla cada vez que realicemos cambios. Hay un problema abierto para eso aquí.

      Ahora, abra http://localhost:3006/ en su navegador web y verá su aplicación renderizada en el lado del servidor.

      Previamente, el código fuente reveló:

      Output

      <div id="root"></div>

      Pero ahora, con los cambios que ha realizado, el código fuente revela:

      Output

      <div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>

      La renderización del lado del servidor convirtió el componente <App> a HTML.

      Conclusión

      En este tutorial, inició una aplicación React y habilitó la renderización del lado del servidor.

      Con esta publicación, solo hemos visto un poco de lo que es posible. Las cosas se complican un poco cuando el direccionamiento, la recuperación de datos o Redux también tengan que ser parte de una aplicación renderizada en el lado del servidor.

      Un beneficio importante de usar SR es tener una aplicación que pueda rastrearse para ver su contenido, incluso para rastreadores que no ejecutan código JavaScript. Esto puede ayudar con la optimización de los motores de búsqueda (SEO) y la transmisión de metadatos a los canales de redes sociales.

      SSR también puede ayudar a menudo con el rendimiento porque una aplicación completamente cargada se envía desde el servidor sobre la primera solicitud. Para aplicaciones no triviales, su valor puede variar porque SSR requiere una configuración que puede volverse algo complicada y crea una mayor carga sobre el servidor. Si utiliza la renderización del lado del servidor para su aplicación React depende de sus necesidades específicas y de qué ventajas tienen más sentido para su caso de uso.

      Si desea aprender más sobre React, eche un vistazo a nuestra serie Cómo crear código en React.js, o consulte nuestra página del tema React para ver ejercicios y proyectos de programación.



      Source link

      Cómo añadir autenticación a su aplicación con Flask-Login


      Introducción

      Permitir a los usuarios iniciar sesión en su aplicación es una de las funciones más frecuentes que añadirá a su aplicación web. Este artículo explicará cómo añadir autenticación a su aplicación Flask con el paquete Flask-Login.

      Gif animado de la aplicación Flask y cuadro de inicio de sesión

      Crearemos algunas páginas de registro e inicio de sesión que permiten a los usuarios iniciar sesión y acceder a páginas protegidas que los usuarios que no hayan iniciado sesión no pueden ver. Obtendremos información del modelo de usuario y la mostraremos en nuestras páginas protegidas cuando el usuario inicie sesión para simular el aspecto que tendrá un perfil.

      En este artículo, explicaremos lo siguiente:

      • Usar la biblioteca de Flask-Login para la administración de las sesiones
      • Usar la utilidad Flask integrada para autenticar contraseñas
      • Añadir páginas protegidas a nuestra aplicación solo para los usuarios con sesión iniciada
      • Usar Flask-SQLAlchemy para crear un modelo de usuario
      • Crear formularios de registro e inicio de sesión para que nuestros usuarios creen cuentas e inicien sesión
      • Devolver mensajes intermitentes de error a los usuarios cuando algo falle
      • Usar la información de la cuenta del usuario para mostrarla en la página de perfil

      El código fuente para este proyecto está disponible en GitHub.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      Nuestra aplicación usará el patrón de fábrica de aplicación Flask con modelos. Tendremos un modelo para gestionar todo lo relacionado con la autenticación, y otro para nuestras rutas regulares, que incluyen el índice y la página de perfil protegida. En una aplicación real, puede desglosar la funcionalidad de cualquier forma que quiera, pero la solución explicada aquí funcionará bien para este tutorial.

      Aquí, tiene un diagrama que muestra cómo se verá la estructura de archivos de su proyecto una vez que haya completado el tutorial:

      .
      └── flask_auth_app
          └── project
              ├── __init__.py       # setup our app
              ├── auth.py           # the auth routes for our app
              ├── db.sqlite         # our database
              ├── main.py           # the non-auth routes for our app
              ├── models.py         # our user model
              └── templates
                  ├── base.html     # contains common layout and links
                  ├── index.html    # show the home page
                  ├── login.html    # show the login form
                  ├── profile.html  # show the profile page
                  └── signup.html   # show the signup form
      

      A medida que avancemos en el tutorial, crearemos estos directorios y archivos.

      Paso 1: Instalar paquetes

      Estos son los tres paquetes principales que necesitamos para nuestro proyecto:

      • Flask
      • Flask-Login: para administrar las sesiones del usuario tras la autenticación
      • Flask-SQLAlchemy: para representar el modelo de usuario y la interfaz con nuestra base de datos

      Usaremos SQLite para evitar tener que instalar dependencias adicionales para la base de datos.

      Primero, empezaremos por crear el directorio del proyecto:

      A continuación, debemos navegar al directorio del proyecto:

      Querrá crear un entorno Python si no tiene uno. Dependiendo de cómo se instaló Python en su equipo, sus comandos tendrán un aspecto similar a:

      • python3 -m venv auth
      • source auth/bin/activate

      Nota: Puede consultar el tutorial relevante a su entorno local para configurar venv.

      Ejecute los siguientes comandos desde su entorno virtual para instalar los paquetes necesarios:

      • pip install flask flask-sqlalchemy flask-login

      Ahora que instaló los paquetes, está listo para crear el principal archivo de la aplicación.

      Paso 2: Crear el archivo principal de la aplicación

      Empezaremos creando un directorio project:

      El primer archivo en el que trabajaremos será el archivo __init__.py para nuestro proyecto:

      Este archivo tendrá la función de crear nuestra aplicación, que iniciará la base de datos y registrará nuestros modelos. En este momento, esto no hará mucho, pero será necesario para el resto de nuestra aplicación. Debemos iniciar SQLAlchemy, establecer algunos valores de configuración y registrar nuestros modelos aquí.

      project/__init__.py

      from flask import Flask
      from flask_sqlalchemy import SQLAlchemy
      
      # init SQLAlchemy so we can use it later in our models
      db = SQLAlchemy()
      
      def create_app():
          app = Flask(__name__)
      
          app.config['SECRET_KEY'] = 'secret-key-goes-here'
          app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
      
          db.init_app(app)
      
          # blueprint for auth routes in our app
          from .auth import auth as auth_blueprint
          app.register_blueprint(auth_blueprint)
      
          # blueprint for non-auth parts of app
          from .main import main as main_blueprint
          app.register_blueprint(main_blueprint)
      
          return app
      

      Ahora que tenemos el archivo principal de la aplicación, podemos comenzar a añadir nuestras rutas.

      Paso 3: Añadir rutas

      Para nuestras rutas, usaremos dos modelos. Para nuestro modelo principal, tendremos una página principal (/) y una página de perfil (/profile) para cuando iniciemos sesión. Si el usuario intenta acceder a la página de perfil sin iniciar sesión, se lo enviará a la ruta de inicio de sesión.

      Para nuestro modelo de autenticación, tendremos rutas para recuperar la página de inicio de sesión (/login) y la página de registro (/sign-up). También tendremos rutas para gestionar las solicitudes POST desde ambas rutas. Finalmente, tendremos una ruta para cerrar sesión (/logout) para cerrar la sesión de un usuario activo.

      Por el momento, definiremos login, signup y logout con retornos simples. Los repasaremos más adelante y los actualizaremos con la funcionalidad deseada.

      Primero, cree main.py para su main_blueprint:

      project/main.py

      from flask import Blueprint
      from . import db
      
      main = Blueprint('main', __name__)
      
      @main.route('/')
      def index():
          return 'Index'
      
      @main.route('/profile')
      def profile():
          return 'Profile'
      

      A continuación, cree auth.py para su auth_blueprint:

      project/auth.py

      from flask import Blueprint
      from . import db
      
      auth = Blueprint('auth', __name__)
      
      @auth.route('/login')
      def login():
          return 'Login'
      
      @auth.route('/signup')
      def signup():
          return 'Signup'
      
      @auth.route('/logout')
      def logout():
          return 'Logout'
      

      En un terminal, puede configurar los valores FLASK_APP y FLASK_DEBUG:

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      La variable de entorno FLASK_APP indica a Flask cómo cargar la aplicación. Debería apuntar hacia donde está create_app. Para nuestros fines, apuntaremos al directorio project.

      La variable de entorno FLASK_DEBUG se habilita configurándola en 1. Esto habilitará un depurador que mostrará los errores de la aplicación en el navegador.

      Asegúrese de que está en el directorio flask_auth_app y, a continuación, ejecute el proyecto:

      Ahora, en un navegador web, debería poder navegar a las cinco URL posibles y ver el texto devuelto que se definió en auth.py y main.py.

      Por ejemplo, visitar localhost:5000/profile muestra: Profile:

      Captura de pantalla del proyecto en el puerto localhost 5000 en el navegador

      Ahora que ya verificamos que nuestras rutas se comportan como se espera, podemos crear las plantillas.

      Paso 4: Crear plantillas

      Ahora crearemos las plantillas usadas en nuestra aplicación. Este es el primer paso antes de poder implementar la funcionalidad real de inicio de sesión. Nuestra aplicación usará cuatro plantillas:

      • index.html
      • profile.html
      • login.html
      • signup.html

      También tendremos una plantilla base que tendrá un código común para cada una de las páginas. En este caso, la plantilla base tendrá enlaces de navegación y el diseño general de la página. Vamos a crearlas ahora.

      Primero, cree un directorio templates en el directorio project:

      • mkdir -p project/templates

      A continuación, cree base.html:

      • nano project/templates/base.html

      A continuación, añada el siguiente código al archivo base.html:

      project/templates/base.html

      <!DOCTYPE html>
      <html>
      
      <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Flask Auth Example</title>
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
      </head>
      
      <body>
          <section class="hero is-primary is-fullheight">
      
              <div class="hero-head">
                  <nav class="navbar">
                      <div class="container">
      
                          <div id="navbarMenuHeroA" class="navbar-menu">
                              <div class="navbar-end">
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
                                      Home
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
                                      Profile
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
                                      Login
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
                                      Sign Up
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
                                      Logout
                                  </a>
                              </div>
                          </div>
                      </div>
                  </nav>
              </div>
      
              <div class="hero-body">
                  <div class="container has-text-centered">
                     {% block content %}
                     {% endblock %}
                  </div>
              </div>
          </section>
      </body>
      
      </html>
      

      Este código creará una serie de enlaces de menú a cada página de la aplicación y un área donde aparecerá el contenido.

      Nota: En segundo plano, estamos usando Bulma para gestionar el estilo y la distribución. Para aprender más sobre Bluma, considere leer la documentación oficial de Bulma.

      A continuación, cree templates/index.html:

      • nano project/templates/index.html

      Añada el siguiente código al archivo recién creado para añadir contenido a la página:

      project/templates/index.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Flask Login Example
      </h1>
      <h2 class="subtitle">
        Easy authentication and authorization in Flask.
      </h2>
      {% endblock %}
      

      Este código creará una página de índice básica con un título y un subtítulo.

      A continuación, cree templates/login.html:

      • nano project/templates/login.html

      Este código genera una página de inicio con campos para Correo electrónico y Contraseña. También hay una casilla de verificación para “recordar” una sesión iniciada.

      project/templates/login.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Login</h3>
          <div class="box">
              <form method="POST" action="/login">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Your Password">
                      </div>
                  </div>
                  <div class="field">
                      <label class="checkbox">
                          <input type="checkbox">
                          Remember me
                      </label>
                  </div>
                  <button class="button is-block is-info is-large is-fullwidth">Login</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      A continuación, cree templates/signup.html:

      • nano project/templates/signup.html

      Añada el siguiente código para crear una página de registro con campos para correo electrónico, nombre y contraseña:

      project/templates/signup.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Sign Up</h3>
          <div class="box">
              <form method="POST" action="/signup">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Password">
                      </div>
                  </div>
      
                  <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      A continuación, cree templates/profile.html:

      • nano project/templates/profile.html

      Añada este código para crear una página sencilla con un título codificado de forma rígida para darle la bienvenida a Anthony:

      project/templates/profile.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Welcome, Anthony!
      </h1>
      {% endblock %}
      

      Más adelante, añadiremos un código para saludar dinámicamente a cualquier usuario.

      Una vez que haya añadido las plantillas, podremos actualizar las instrucciones de retorno en cada una de las rutas que tenemos para que devuelvan las plantillas en vez del texto.

      A continuación, actualice main.py modificando la línea de importación y las rutas para index y profile:

      project/main.py

      from flask import Blueprint, render_template
      ...
      @main.route('/')
      def index():
          return render_template('index.html')
      
      @main.route('/profile')
      def profile():
          return render_template('profile.html')
      

      Ahora, actualizará auth.py modificando la línea de importación y las rutas para login y signup:

      project/auth.py

      from flask import Blueprint, render_template
      ...
      @auth.route('/login')
      def login():
          return render_template('login.html')
      
      @auth.route('/signup')
      def signup():
          return render_template('signup.html')
      

      Una vez que haya realizado estos cambios, así lucirá la página de registro si navega a /sign-up:

      Página de registro en /signup

      También debería poder ver las páginas para /, /login y /profile.

      No trabajaremos con /logout por ahora porque no mostrará una plantilla cuando esté listo.

      Paso 5: Crear modelos de usuario

      Nuestro modelo de usuario representa qué significa para nuestra aplicación tener un usuario. Tendremos campos para una dirección de correo electrónico, contraseña y nombre. En su aplicación, puede decidir que quiere guardar mucha más información por usuario. Puede añadir cosas como fecha de nacimiento, perfil, imagen, ubicación o cualquier preferencia del usuario.

      Los modelos creados en Flask-SQLAlchemy se representan mediante clases y, luego, se trasladan a tablas en una base de datos. Los atributos de esas clases se convierten en columnas para esas tablas.

      Ahora crearemos ese modelo de usuario:

      Este código crea un modelo de usuario con columnas para id, email, password y name:

      project/models.py

      from . import db
      
      class User(db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Ahora que creó un modelo de usuario, puede configurar su base de datos.

      Paso 6: Configurar la base de datos

      Como se indicó en los requisitos previos, usaremos una base de datos SQLite. Podríamos crear una base de datos SQLite por nuestra cuenta, pero dejemos que Flask-SQLAlchemy lo haga por nosotros. Ya tenemos la ruta de la base de datos especificada en el archivo __init__.py, así que solo necesitamos indicar a Flask-SQLAlchemy que cree la base de datos en el REPL de Python.

      Si detiene su aplicación y abre un REPL de Python, podemos crear la base de datos usando el método create_all en el objeto db. Asegúrese de que aún está en el entorno virtual y en el directorio flask_auth_app.

      • from project import db, create_app
      • db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

      Nota: Si el uso del intérprete de Python es nuevo para usted, puede consultar la documentación oficial.

      Ahora, verá un archivo db.sqlite en el directorio de su proyecto. Esta base de datos contendrá nuestra tabla de usuario.

      Paso 7: Configurar la función de autorización

      Para nuestra función de registro, tomaremos los datos que escriba el usuario en el formulario y los añadiremos a nuestra base de datos. Antes de añadirlo, debemos asegurarnos de que el usuario no existe ya en la base de datos. Si no es así, debemos asegurarnos de autenticar la contraseña antes de colocarla en la base de datos, porque no queremos que nuestras contraseñas se almacenen en archivo de texto.

      Empezaremos por añadir una segunda función para gestionar los datos del formulario POST. En esta función, recopilaremos primero los datos ingresados por el usuario.

      Cree la función y añada una redirección en la parte inferior. Esto proporcionará una experiencia de usuario de un registro correcto y se lo redirigirá a la página de inicio de sesión.

      Actualice auth.py modificando la línea de importación e implementando signup_post:

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          # code to validate and add user to database goes here
          return redirect(url_for('auth.login'))
      

      Ahora, añadiremos el resto del código necesario para registrar a un usuario.

      Para comenzar, tendremos que usar el objeto de solicitud para obtener los datos del formulario.

      Continúe para actualizar auth.py añadiendo importaciones e implementando signup_post:

      auth.py

      from flask import Blueprint, render_template, redirect, url_for, request
      from werkzeug.security import generate_password_hash, check_password_hash
      from .models import User
      from . import db
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          email = request.form.get('email')
          name = request.form.get('name')
          password = request.form.get('password')
      
          user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database
      
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              return redirect(url_for('auth.signup'))
      
          # create a new user with the form data. Hash the password so the plaintext version isn't saved.
          new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))
      
          # add the new user to the database
          db.session.add(new_user)
          db.session.commit()
      
          return redirect(url_for('auth.login'))
      

      Nota: El almacenamiento de contraseñas en archivos de texto se considera una mala práctica de seguridad. Normalmente, querrá usar un algoritmo de autenticación complejo y una sal de contraseña para proteger las contraseñas.

      Paso 8: Probar el método de registro

      Ahora que tenemos el método de registro, deberíamos poder crear un nuevo usuario. Use el formulario para crear un usuario.

      Hay dos formas de verificar si el registro funcionó: puede usar un visor de base de datos para ver la fila que se añadió a su tabla o puede intentar registrarse con la misma dirección de correo de nuevo y, si recibe un error, sabe que el primer correo electrónico se guardó correctamente. Hagamos eso.

      Podemos añadir un código para permitir al usuario saber que el correo electrónico ya existe e indicarle que vaya a la página de inicio de sesión. Al invocar la función flash, enviaremos un mensaje a la siguiente solicitud que, en este caso, es la redirección. La página a la que llegamos tendrá acceso a ese mensaje en la plantilla.

      Primero, añadimos flash antes de redirigir a nuestra página de registro.

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for, request, flash
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          ...
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              flash('Email address already exists')
              return redirect(url_for('auth.signup'))
      

      Para obtener el mensaje intermitente en la plantilla, podemos añadir este código sobre el formulario. Esto mostrará el mensaje directamente arriba del formulario.

      project/templates/signup.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}. Go to <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}">login page</a>.
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/signup">
      

      Cuadro de registro mostrando el mensaje

      Paso 9: Añadir el método de inicio de sesión

      El método de inicio de sesión es similar a la función de registro porque tomaremos la información del usuario y haremos algo con ella. En este caso, compararemos la dirección de correo electrónico introducida para ver si está en la base de datos. Si es así, probaremos la contraseña proporcionada por el usuario autenticando la contraseña que el usuario introduce y comparándola con la contraseña autenticada en la base de datos. Sabemos que el usuario introdujo la contraseña correcta cuando ambas contraseñas autenticadas coinciden.

      Una vez que el usuario haya pasado la comprobación de contraseña, sabemos que tiene las credenciales correctas y puede iniciar sesión usando Flask-Login. Al invocar login_user, Flask-Login creará una sesión para ese usuario que persistirá mientras el usuario permanezca con sesión iniciada, lo que permitirá al usuario ver las páginas protegidas.

      Podemos comenzar con una nueva ruta para gestionar los datos que ya fueron procesados por POST. Redirigiremos a la página de perfil cuando el usuario inicie sesión correctamente.

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          # login code goes here
          return redirect(url_for('main.profile'))
      

      Ahora, debemos verificar si el usuario tiene las credenciales correctas:

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          email = request.form.get('email')
          password = request.form.get('password')
          remember = True if request.form.get('remember') else False
      
          user = User.query.filter_by(email=email).first()
      
          # check if the user actually exists
          # take the user-supplied password, hash it, and compare it to the hashed password in the database
          if not user or not check_password_hash(user.password, password):
              flash('Please check your login details and try again.')
              return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page
      
          # if the above check passes, then we know the user has the right credentials
          return redirect(url_for('main.profile'))
      

      Añadiremos el bloque en la plantilla para que el usuario pueda ver el mensaje intermitente. Al igual que con el formulario de registro, añadiremos el potencial mensaje de error directamente arriba del formulario:

      project/templates/login.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/login">
      

      Ahora podemos decir que un usuario inició sesión correctamente, pero no tenemos nada para registrar la información del usuario. Aquí es donde traemos a Flask-Login para gestionar las sesiones de usuario.

      Antes de comenzar, necesitamos algunas cosas para que Flask-Login funcione. Comience añadiendo UserMixin a su modelo de usuario. El UserMixin añadirá atributos de Flask-Login al modelo de forma que Flask-Login pueda trabajar con él.

      models.py

      from flask_login import UserMixin
      from . import db
      
      class User(UserMixin, db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      A continuación, necesitamos especificar nuestro cargador de usuario. Un cargador de usuario indica a Flask-Login cómo encontrar un usuario específico a partir del identificador que se almacena en su cookie de sesión. Podemos añadir esto en nuestra función create_app junto con el código init para Flask-Login:

      project/__init__.py

      ...
      from flask_login import LoginManager
      ...
      def create_app():
          ...
          db.init_app(app)
      
          login_manager = LoginManager()
          login_manager.login_view = 'auth.login'
          login_manager.init_app(app)
      
          from .models import User
      
          @login_manager.user_loader
          def load_user(user_id):
              # since the user_id is just the primary key of our user table, use it in the query for the user
              return User.query.get(int(user_id))
      

      Finalmente, podemos añadir la función login_user justo antes de redirigir a la página de perfil para crear la sesión:

      project/auth.py

      from flask_login import login_user
      from .models import User
      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          ...
          # if the above check passes, then we know the user has the right credentials
          login_user(user, remember=remember)
          return redirect(url_for('main.profile'))
      

      Con la configuración de Flask-Login, podemos usar la ruta /login. Cuando todo esté listo, verá la página de perfil.

      Página de perfil con

      Paso 10: Proteger las páginas

      Si su nombre no es Anthony, verá que el nombre está mal. Lo que queremos es que el perfil muestre el nombre en la base de datos. Primero debemos proteger la página y, luego, acceder a los datos del usuario para obtener el nombre.

      Para proteger una página cuando se usa Flask-Login, añadiremos el decorador @login_required entre la ruta y la función. Esto evitará que un usuario que no haya iniciado sesión vea la ruta. Si el usuario no inició sesión, se lo redirigirá a la página de inicio, según la configuración de Flask-Login.

      Con las rutas representadas con el decorador @login_required, tenemos la capacidad de usar el objeto current_user dentro de la función. Este current_user representa al usuario de la base de datos, y podemos acceder a todos los atributos de ese usuario con notación por puntos. Por ejemplo, current_user.email, current_user.password y current_user.name y current_user.id devolverán los valores reales almacenados en la base de datos para el usuario con sesión iniciada.

      Usaremos el nombre del usuario actual y lo enviaremos a la plantilla. Usaremos ese nombre y mostraremos su valor.

      project/main.py

      from flask_login import login_required, current_user
      ...
      @main.route('/profile')
      @login_required
      def profile():
          return render_template('profile.html', name=current_user.name)
      

      A continuación, en el archivo profile.html, actualice la página para mostrar el valor name:

      project/templates/profile.html

      ...
      <h1 class="title">
        Welcome, {{ name }}!
      </h1>
      

      Cuando vayamos a nuestra página de perfil, veremos que aparece el nombre del usuario.

      Página de bienvenida del usuario con el nombre del usuario con sesión iniciada actualmente

      Lo último que podemos hacer es actualizar la vista de cierre de sesión. Podemos invocar la función logout_user para cerrar sesión. Tenemos el decorador @login_required porque no tiene sentido que un usuario cierre una sesión que no inició en primer lugar.

      project/auth.py

      from flask_login import login_user, logout_user, login_required
      ...
      @auth.route('/logout')
      @login_required
      def logout():
          logout_user()
          return redirect(url_for('main.index'))
      

      Tras cerrar sesión e intentar ver la página del perfil, vemos que aparece un mensaje de error. Esto es porque Flask-Login muestra un mensaje intermitente para nosotros cuando el usuario no tiene permiso para acceder a una página.

      Página de inicio con un mensaje que muestra que el usuario debe iniciar sesión para acceder a la página

      Una última cosa que podemos hacer es poner declaraciones if en las plantillas para mostrar solo los enlaces relevantes al usuario. Antes de que el usuario inicie sesión, tendrá la opción de iniciar sesión o registrarse. Tras haber iniciado sesión, el usuario puede ir a su perfil o cerrar sesión:

      templates/base.html

      ...
      <div class="navbar-end">
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
              Home
          </a>
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
              Profile
          </a>
          {% endif %}
          {% if not current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
              Login
          </a>
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
              Sign Up
          </a>
          {% endif %}
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
              Logout
          </a>
          {% endif %}
      </div>
      

      Página de inicio con la navegación de las páginas Principal, Inicio de sesión y Registro en la parte superior de la pantalla

      Con eso, creó correctamente su aplicación con autenticación.

      Conclusión

      Usamos Flask-Login y Flask-SQLAlchemy para crear un sistema de inicio de sesión para nuestra aplicación. Vimos cómo autenticar a un usuario creando primero un modelo de usuario y almacenando la información del usuario. A continuación, tuvimos que verificar que la contraseña del usuario fuera correcta autenticando la contraseña desde el formulario y comparándola con la almacenada en la base de datos. Finalmente, añadimos autorización a nuestra aplicación usando el decorador @login_required en una página de perfil de forma que solo los usuarios con sesión iniciada puedan verla.

      Lo que creamos en este tutorial será suficiente para aplicaciones más pequeñas pero, si quiere tener más funcionalidad desde el principio, quizá desee considerar usar las bibliotecas Flask-User o Flask-Security, que se desarrollaron a partir de la biblioteca Flask-Login.



      Source link