Python Django | Autenticación de Google y obtención de correos desde cero

La autenticación de Google y la obtención de correos desde cero significan que no se utiliza ningún módulo que ya haya configurado este proceso de autenticación. Usaremos el cliente python de la API de Google, oauth2client que es proporcionado por Google. A veces, es realmente difícil implementar esta autenticación de Google con estas bibliotecas, ya que no había documentación adecuada disponible. Pero después de completar esta lectura, las cosas se aclararán por completo.

Ahora vamos a crear el proyecto Django 2.0 y luego implementar los servicios de autenticación de Google y luego extraer los correos. Estamos extrayendo el correo solo para mostrar cómo se puede pedir permiso después de autenticarlo.

Paso #1: Creando el Proyecto Django

El primer paso es crear un entorno virtual y luego instalar las dependencias. Así que estaremos usando venv:

mkdir google-login && cd google-login

python3.5 -m venv myvenv
source myvenv/bin/activate

Este comando creará una carpeta myvenv a través de la cual acabamos de activar el entorno virtual. Ahora escriba

pip freeze

Entonces no debe ver dependencias instaladas en él. Ahora lo primero es instalar Django:

pip install Django==2.0.7

Esa es la versión de Django que usamos, pero siéntete libre de usar cualquier otra versión. Ahora, el siguiente paso es crear un proyecto, llamémoslo gfglogin:

django-admin startproject gfglogin .

Dado que estamos dentro del directorio de inicio de sesión de google, es por eso que queremos que el proyecto django esté en ese directorio actual solo para eso, necesita usar ‘. ‘ al final para la indicación de directorio actual. Luego cree una aplicación para separar la lógica del proyecto principal, así que cree una aplicación llamada gfgauth:

django-admin startapp gfgauth

Entonces, la terminal general se verá así:

Desde que creamos una aplicación. Agregue el nombre de esa aplicación settings.pyen la INSTALLED_APP lista. Ahora tenemos el proyecto Django en ejecución, así que migrémoslo primero y luego verifiquemos si hay algún error o no.

python manage.py makemigrations
python manage.py migrate
python manage.py runserver

Entonces, después de migrar, uno debería poder ejecutar el servidor y ver la página de inicio de Django en esa URL en particular.

 
Paso #2: Instalar dependencias

Ya que tenemos el proyecto funcionando con éxito, instalemos los requisitos básicos. Primero, necesitamos googleapiclient, esto es necesario porque tenemos que crear un objeto de recurso que ayude a interactuar con la API. Entonces, para ser precisos, haremos uso del método `build` a partir de él.

Instalar:

pip install google-api-python-client==1.6.4

Ahora, el segundo módulo es oauth2client, esto se asegurará de toda la autenticación, credencial, flujos y muchas cosas más complejas, por lo que es importante usar esto.

pip install oauth2client==4.1.2

Y por último, instale jsonpickle, (por si acaso no está instalado) porque lo usará oauth2client al hacer CredentalsField.

pip install jsonpickle==0.9.6

Así que estas son las únicas dependencias que necesitamos. Ahora pasemos a la parte de codificación y veamos cómo funciona.
 
Paso #3: Creando modelos

Use modelos para almacenar las credenciales que obtenemos de una API, por lo que solo hay 2 campos principales que deben cuidarse. El primero es id , que será ForeignKey y el segundo es credential que será igual a CredentialsField. Este campo debe importarse desde oauth2client. Entonces nuestro models.pyse verá así:

from django.contrib import admin
from django.contrib.auth.models import User
from django.db import models
from oauth2client.contrib.django_util.models import CredentialsField
  
  
class CredentialsModel(models.Model):
    id = models.ForeignKey(User, primary_key = True, on_delete = models.CASCADE)
    credential = CredentialsField()
    task = models.CharField(max_length = 80, null = True)
    updated_time = models.CharField(max_length = 80, null = True)
  
  
class CredentialsAdmin(admin.ModelAdmin):
    pass,

Actualmente task y updated_time son simplemente campos adicionales agregados, por lo tanto, se pueden eliminar. Entonces, esta credencial contendrá los datos de la credencial en la base de datos.

Pauta importante:

Cuando importamos CredentialsField, automáticamente el __init__método se ejecuta en la parte posterior y si notará el código en la
/google-login/myvenv/lib/python3.5/site-packages/oauth2client/contrib/django_util/__init__.py línea de ruta 233

Están importando urlresolvers para poder utilizar el método inverso. Ahora, el problema es que estos urlresolvers se eliminaron después de Django 1.10 o Django 1.11. Si está trabajando en Django 2.0, dará un error que indica que no se pueden encontrar los urlresolvers o que no están allí.

Ahora, para superar este problema, necesitamos cambiar 2 líneas, primero reemplace esa importación from django.core import urlresolvers afrom django.urls import reverse

Y luego reemplace la Línea 411 urlresolvers.reverse(...) areverse(...)

Ahora debería poder ejecutarlo con éxito.

Después de crear estos modelos:

python manage.py makemigrations
python manage.py migrate

 
Paso #4: Creando Vistas

En este momento, solo tenemos 3 vistas principales para manejar las requests. Lo primero es mostrar la página de inicio, el estado, el botón de Google para que podamos enviar requests de autenticación. La segunda vista se activará cuando se haga clic en el botón de Google, lo que significa una solicitud de AJAX. El tercero será manejar la solicitud de devolución de Google para que podamos aceptar el token de acceso y guardarlo en nuestra base de datos.

Primero, hagamos lo de la autenticación de Google:

Entonces, en este momento, debemos especificar el flujo a la API, qué permisos debemos solicitar, cuál es mi clave secreta y redirigir la URL. Así que para hacer eso ingrese:

FLOW = flow_from_clientsecrets(
    settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON,
    scope='https://www.googleapis.com/auth/gmail.readonly',
    redirect_uri='http://127.0.0.1:8000/oauth2callback',
    prompt='consent')

Como puede notar settings.GOOGLE_OAUTH2_CLIENT_SECRETS_JSON, vaya a settings.pyarchivo y escriba:

GOOGLE_OAUTH2_CLIENT_SECRETS_JSON = 'client_secrets.json'

Esto le dice a Django que donde json está presente el archivo. Posteriormente descargaremos este archivo. Después de especificar el flujo, comencemos la lógica.

Cada vez que necesitamos ver si alguien está autorizado o no, primero verificamos en nuestra base de datos si las credenciales de ese usuario ya están presentes o no. De lo contrario, hacemos requests a la URL de la API y luego obtenemos las credenciales.

def gmail_authenticate(request):
    storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
    credential = storage.get()
  
    if credential is None or credential.invalid:
        FLOW.params['state'] = xsrfutil.generate_token(settings.SECRET_KEY,
                                                              request.user)
        authorize_url = FLOW.step1_get_authorize_url()
        return HttpResponseRedirect(authorize_url)
    else:
        http = httplib2.Http()
        http = credential.authorize(http)
        service = build('gmail', 'v1', http = http)
        print('access_token = ', credential.access_token)
        status = True
  
        return render(request, 'index.html', {'status': status})

Usamos DjangoORMStorage (que es proporcionado por oauth2client) para que podamos almacenar y recuperar credenciales del almacén de datos de Django. Entonces necesitamos pasar 4 parámetros para ello. Primero está la clase modelo que tiene CredientialsField dentro. El segundo es el ID único que tiene credenciales que significa nombre de clave, el tercero es el valor de clave que tiene las credenciales y el último es el nombre de CredentialsField que especificamos en models.py.

Luego obtenemos el valor del almacenamiento y vemos si es válido o no. Si no es válido, creamos un token de usuario y obtenemos uno para autorizar la URL, donde redirigimos al usuario a la página de inicio de sesión de Google. Después de redirigir, el usuario completará el formulario y una vez que Google autorice al usuario, Google enviará datos a la URL de devolución de llamada con access_token la que lo haremos más adelante. Ahora, en caso de que las credenciales del usuario ya estuvieran presentes, volverá a verificar las credenciales y le devolverá el token de acceso o, a veces, el token de acceso actualizado en caso de que el anterior haya expirado.

Ahora necesitamos manejar la URL de devolución de llamada, para hacer eso:

def auth_return(request):
    get_state = bytes(request.GET.get('state'), 'utf8')
    if not xsrfutil.validate_token(settings.SECRET_KEY, get_state,
                                   request.user):
        return HttpResponseBadRequest()
  
    credential = FLOW.step2_exchange(request.GET.get('code'))
    storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
    storage.put(credential)
  
    print("access_token: % s" % credential.access_token)
    return HttpResponseRedirect("/")

Ahora, dentro de la URL de devolución de llamada, cuando recibimos una respuesta de Google, capturamos los datos y obtenemos el estado de ellos, el estado no es más que el token que generamos mediante generateToken. Entonces lo que hacemos es que validamos el token con secret_key, el token que generamos y con el usuario que lo generó. Estas cosas se verifican mediante un xsrfutil.validate_tokenmétodo que garantiza que el token no sea demasiado antiguo y que se haya generado solo en un momento determinado. Si estas cosas no funcionan bien, le dará un error; de lo contrario, irá al siguiente paso y compartirá el código de la respuesta de devolución de llamada con Google para que pueda obtener el token de acceso.

Entonces, esta fue una verificación de 2 pasos y después de obtener con éxito la credencial, la guardamos en el almacén de datos de Django usando DjangoORMStorage porque solo podemos obtener y almacenar la credencial en CredentialsField. Una vez que lo almacenemos, podemos redirigir al usuario a cualquier página en particular y así es como puede obtener access_token.

Ahora vamos a crear una página de inicio que dirá si el usuario ha iniciado sesión o no.

def home(request):
    status = True
  
    if not request.user.is_authenticated:
        return HttpResponseRedirect('admin')
  
    storage = DjangoORMStorage(CredentialsModel, 'id', request.user, 'credential')
    credential = storage.get()
  
    try:
        access_token = credential.access_token
        resp, cont = Http().request("https://www.googleapis.com/auth/gmail.readonly",
                                     headers ={'Host': 'www.googleapis.com',
                                             'Authorization': access_token})
    except:
        status = False
        print('Not Found')
  
    return render(request, 'index.html', {'status': status})

En este momento, asumimos que el usuario está autenticado en Django, lo que significa que el usuario ya no es anónimo y tiene información guardada en la base de datos. Ahora, para tener soporte para el usuario anónimo, podemos eliminar las comprobaciones de credenciales en la base de datos o crear un usuario temporal.

Volviendo a la vista de inicio, primero verificaremos si el usuario está autenticado o no, lo que significa que el usuario no es anónimo, si es así, haga que inicie sesión; de lo contrario, primero verifique las credenciales. Si el usuario ya inició sesión desde Google, mostrará Estado como Verdadero; de lo contrario, mostrará Falso.

Ahora, llegando a las plantillas, creemos una. Primero vaya a la carpeta raíz y cree una carpeta llamada ‘plantillas’, luego dentro de eso cree index.html:

{% load static %}
<!DOCTYPE html>
<html lang="en">
  
<head>
    <meta charset="UTF-8">
    <script src="{% static 'js/main.js' %}"></script>
    <title>Google Login</title>
</head>
<body>
  
<div>
    <div>
        {% if not status %}
            <a href="/gmailAuthenticate" onclick="gmailAuthenticate()" title="Google">Google</a>
        {% else %}
            <p>Your are verified</p>
        {% endif %}
    </div>
  
</div>
</body>
</html>

Ahora, esta página está muy simplificada, por lo que no hay CSS ni estilo, solo un enlace simple para verificar. Ahora también notará el archivo js . así que de nuevo ve a la carpeta raíz y crea un directorio comostatic/js/

Y dentro de js crea un archivo javascript main.js:

function gmailAuthenticate(){
    $.ajax({
        type: "GET",
        url: "ajax/gmailAuthenticate",
        // data: '',
        success: function (data) {
            console.log('Done')
        }
    });
};

Este archivo js se usó para separar la lógica del archivo HTML y también para hacer una llamada AJAX a Django. Ahora tenemos todas las partes hechas para las vistas.
 
Paso #5: Creación de URL y configuraciones básicas

En las URL del proyecto principal significa gfglogin/urls.pyeditar y poner:

from django.contrib import admin
from django.urls import path, include
  
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('gfgauth.urls')),
]

Porque necesitamos probar el funcionamiento de la aplicación gfgauth. Ahora dentro gfgauth/urls.py escribe:

from django.conf.urls import url
from . import views
  
urlpatterns = [
    url(r'^gmailAuthenticate', views.gmail_authenticate, name ='gmail_authenticate'),
    url(r'^oauth2callback', views.auth_return),
    url(r'^$', views.home, name ='home'),
]

Como puede ver, gmailAuthenticate es para llamadas AJAX, oauth2callback es para la URL de devolución de llamada y la última es la URL de la página de inicio. Ahora, antes de ejecutar, hay algunas configuraciones de las que no hemos hablado:

En settings.pynecesitas editar:

  1. En la lista PLANTILLAS agregue ‘plantillas’ dentro de la lista DIRS.
  2. Al final del archivo settings.py agregue:
    STATIC_URL = '/static/'
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, 'static'),
    )
    
    GOOGLE_OAUTH2_CLIENT_SECRETS_JSON = 'client_secrets.json'
    

Así que acabamos de especificar dónde están presentes las plantillas y los archivos estáticos y, lo que es más importante, dónde está el archivo json secreto del cliente de google oauth2. Ahora vamos a descargar este archivo.
 
Paso #6: Generación del archivo secreto del cliente Oauth2

Dirígete a la página de Google Developer Console y crea un proyecto y asígnale el nombre que quieras. Después de crearlo, diríjase al panel del proyecto y haga clic en el menú de navegación que se encuentra en la parte superior izquierda. Luego haga clic en servicios API y luego en la página de credenciales. Haga clic en crear credenciales (es posible que deba establecer el nombre del producto antes de continuar, así que hágalo primero). Ahora seleccione la aplicación web ya que estamos usando Django. Después de esto, especifique el nombre y luego simplemente vaya a redirigir URI y allí escriba:

http://127.0.0.1:8000/oauth2callback

Y luego guárdalo. No necesita especificar los orígenes de Javascript autorizados, así que déjelo en blanco por ahora. Después de guardarlo, podrá ver todas sus credenciales, simplemente descargue las credenciales, se guardarán con algunos nombres aleatorios, así que simplemente vuelva a formatear el nombre del archivo y escriba ‘client_secrets’ y asegúrese de que esté en formato json. Luego guárdelo y péguelo en la carpeta raíz del proyecto Django (donde se encuentra manage.py).
 
Paso #7: Ejecutarlo

Ahora vuelve a comprobar si todo es correcto o no. Asegúrate de haberlo migrado. Además, antes de continuar, cree un superusuario para que ya no sea anónimo:

python3.5 manage.py createsuperuser

Escriba todos los detalles necesarios y luego haga:

python3.5 manage.py runserver

Y ve a http://127.0.0.1:8000

Verás esto:

Lo cual está perfectamente bien, ahora escriba sus credenciales de superusuario aquí y luego podrá ver el panel de administración. Solo evita eso y vuelve a ir a http://127.0.0.1:8000

Ahora debería poder ver el enlace de Google, ahora haga clic en él y verá:

Ahora, como puede ver, dice Iniciar sesión para continuar con GFG, aquí GFG es el nombre de mi proyecto. Así que está funcionando bien. Ahora ingrese sus credenciales y después de enviar verá:

Dado que estamos solicitando permiso de correos, es por eso que le está pidiendo al usuario que lo permita. En caso de que muestre un error, en la consola de Google es posible que deba activar la API de Gmail en su proyecto. Ahora, una vez que lo permita, obtendrá las credenciales y se guardará dentro de su base de datos. En caso de que el usuario haga clic en Cancelar, deberá escribir algunos códigos más para manejar dicho flujo.

Ahora, en caso de que lo haya permitido, podrá ver el token de acceso en su consola/base de datos. Después de obtener access_token, puede utilizarlo para obtener el correo electrónico del usuario y todo lo demás.

Vea el código completo en este repositorio aquí .

Publicación traducida automáticamente

Artículo escrito por shashank-sharma y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *