Cómo hacer un web login con Google Apps Script


Artículo relacionado con la programación web mediante Google Apps Script
Este artículo ha sido usado como base para implementar un chat con Google Apps Script
Aquí tienes una versión mejorada de este mismo artículo

Hace un tiempo expliqué cómo hacer una web con Google Apps Script . Debido a ese post me han llegado diversas peticiones de como podría hacer un login para acceder a contenido más personalizado o privado.

Como siempre os digo es más fácil de lo que parece.

Este ejemplo contiene un parte de html y una parte de GAS. Evidentemente la parte de html se puede mejorar con CSS u otras tecnologías para hacerlo más atractivo, yo solo os pongo un ejemplo sencillo para que veáis como funciona.

Presupongo que para utilizar este tutorial  ya habéis leído el tutorial para hacer webs con GAS, sino es así revisadlo primero  o iréis perdidos: cómo hacer una web con Google Apps Script

HTML:
<!DOCTYPE html>
<html>
  <head>
    <script>
    function HaEntrado(enter)
    {
        if(enter)
        {
          document.getElementsByName("mensajebienvenida")[0].innerHTML = "Bienvenido";
        }
        else
        {
          document.getElementsByName("mensajebienvenida")[0].innerHTML = "Usuario o password incorrecto";
        }
 
    }
 
    function tryLogin()
    {
        var user=document.getElementsByName("login")[0].value;
        var password=document.getElementsByName("password")[0].value;
        google.script.run.withSuccessHandler(HaEntrado).Login(user,password);
    }
    </script>
 
  </head>

  <body onLoad="setInterval('refresher()',5000);">
  <label name="mensajebienvenida">  Usuari no registrado   </label>
   <section class="container" >
    <div class="login" name="LoginPage">
      <h1>Zona privada para lectores del blog</h1>
      <form method="post" action="index.html">
        <p><input type="text" name="login" value="" placeholder="User"></p>
        <p><input type="password" name="password" value="" placeholder="Password"></p>
        <p class="submit"><input type="submit" name="commit" value="Login" onclick="tryLogin()"></p>
      </form>
    </div>
  </section>

  </body>
</html>

GS:
//Retorna la página principal
function doGet() 
{
  return HtmlService.createHtmlOutputFromFile('index');
}

var archivo_login      = 'https://docs.google.com/spreadsheets/d/1fKu-sk2Tl7K3OD_6vGA-OaDUJ96_tw0NpR433_a8cwo/edit#gid=0';

//Gestiona el login del usuario y nos dice si la contraseña es correcta o no.
function Login(user,password) 
{
  var spreadsheet = SpreadsheetApp.openByUrl(archivo_login);
  var sheet = spreadsheet.getActiveSheet();
  var rows = sheet.getDataRange();
  var numRows = rows.getNumRows();
  var values = rows.getValues();
  var passwordMD5 = Utilities.base64Encode(Utilities.computeDigest(Utilities.DigestAlgorithm.MD5,password));
  
  Logger.log('user:' + user + ' password:' + password);
   
  for (var i = 1; i <= numRows - 1; i++) 
  {
    var row = values[i];
    
    if (row[0] == user )
    {
      if(row[1] ==  passwordMD5)
      {
         sheet.getRange(i+1,3).setValue(row[2]+1);
         return true;
      }
    }
  }
  return false;
}

Si queréis ver un ejemplo funcionando probad a acceder a esta web donde tengo el código funcionando: web login


Si lo probáis podéis usar como usuario y password : usuario0-password0, usuario1-password1, etc...

Si os funciona bien debería apareceros algo de este estilo:


Si os fijáis el password que guardo en el servidor no tiene ninguna relación con el password que se usa para acceder, de forma que si un hacker entrase en el servidor no tendría acceso a los passwords.



Si tenéis cualquier problema al probar este ejemplo decidmelo y os echaré un cable.

NOTA: Si quieres insertar la web que generes en otro sitio tal vez te valga la pena mirar como hacer un iframe de un google apps script

NOTA: Si te da demasiados problemas y necesitas un acabado profesional, puedo ofrecerte mis servicios para tener un login en condiciones por un precio muy asequible

55 comentarios:

  1. buenas lo primero muchas gracias por este aporte y le estaría muy agradecido y me dice como quitar el panel de registro una vez ya he puesto el usuario y las contraseñas correctas.
    De modo que me salga lo de Bienvenido y depues lo que yo quiera.
    gracias:)

    ResponderEliminar
    Respuestas
    1. Es sencillo.... El servidor nos devuelve un string ( un html ) que lo podemos poner donde queramos.
      Si lo que quieres es quitar el panel de login debes poner el html que devuelve el servidor dentro del body de la web, sustituyendo así el código que habia hasta ahora....

      Creo que te estoy liando más que no ayudando... dame unos dias y hago un tutorial para explicarlo mejor, ya verás que es más sencillo de lo que parece.

      Eliminar
  2. Como puede crear, un sistema de registro de nuevos usuarios?

    ResponderEliminar
    Respuestas
    1. Gran pregunta :D . Dame unos días que ahora mismo voy un poco liado y lo monto para que lo tengáis a mano.
      Gracias por la pregunta, estaba esperando que alguien lo pidiera :D

      Eliminar
  3. Por alguna razón, hace dos meses este código funcionaba y ahora no ¿Qué podrá ser?

    ResponderEliminar
    Respuestas
    1. Que problema te da? GAS es un poco puñetero por que a veces google cambia cosas sin avisar... generalmente todo funciona pero a veces tienes sorpresas... dime que te ha pasado y lo miro

      Eliminar
    2. Cuando introduzco usuario y password entra a mi SpreadSheet sin problema (lo sé porque añade 1 al número de accesos del usuario). Pero creo que la función Login(user,password) devuelve "undefined" en lugar de true o false (lo sospecho porque no se ejecuta la función HaEntrado).
      Gracias por tu rápida respuesta

      Eliminar
    3. No me cuadra... hazme copypaste de tu código... lo que me comentas no tiene demasiado sentido... a ver si con el código puedo verlo mejor

      Eliminar
    4. Mi código es exactamente el tuyo (salvo la dirección de la Spreadsheet). Acabo de darme cuenta de que tampoco me funciona tu ejemplo de web login. ¿Será cosa del Chrome?

      Eliminar
    5. Yo uso crhome... y sin problemas. Lo que me comentas no tiene demasiado sentido... me inclinaría más tal vez por un tema de permisos.... prueba a poner ese mismo código en otra web a ver si te vuelve a pedir permisos y se espabila. Sino, deberás tracear y ver exactamente que hace. siento no ser de más ayuda

      Eliminar
  4. En tu web de ejemplo (https://sites.google.com/site/ejemplologin/) tampoco me va bien. Al meter usuario0 y password0 se me queda en blanco la pantalla (desaparece hasta el formulario de login)

    ResponderEliminar
    Respuestas
    1. Ok... estoy convencido que iba, así que me lo tendré que mirar... alguna chorrada que cambiarian los de google.... No se decirte cuando lo tendré... te aviso si lo veo

      Eliminar
    2. Muchas gracias por tu interés. Si descubro yo algo por mi cuenta te aviso.

      Eliminar
    3. Creo que el problema es el botón que envía el formulario. Si a la etiqueta 'form' se le quita action y se saca el botón del formulario puede que funcione. En otras palabras, creo que el problema es la llamada que hace index.html a sí misma.

      Eliminar
    4. Me lo tendré que mirar con calma ( voy un poco liado ultimamente) pero tiene sentido.. hace un tiempo google cambio algo de los scripts llamado a html por temas de seguridad..... creo que existe una solución mejor a tu problema de lo que propones.... a la que pueda me pongo... gracias por colaborar!!

      Eliminar
  5. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  6. La idea me parece muy chula, útil y sencilla de hacer. Como siempre, voy de culo entre unas cosas y otras, pero realmente este proyecto me ha ilusionado. Si es un tema que te hace falta para ya puedes mirarte formularios de google, he visto cosas hechas que darian bastante el pego. Si puedes esperar un poco te lo monto ni que sea el esqueleto. Nos vemos y gracias por tu aporte

    ResponderEliminar
  7. Hola de nuevo

    por completar la idea que en su día comenté para el ampa, al "arrancar" la web en el pc, lee un fichero local txt con el curso que corresponde. Eso pasa a variable y seguido lee datos de un spreadsheet con los nombres de l@s hij@s que filtra por dicho curso, donde con una barra de seleeción pichas sobre el cri@ elegido y luego se valida con una clave también existente en dicho fichero que el padre debe teclear.
    Las actividades a las que se les apuntan, van nuevamente a un spreadsheet y el resto... ticket y mail, como expliqué.
    Un poco liada, pero son muchos temas y cosas...

    ResponderEliminar
    Respuestas
    1. no lo haria con txt , lo haría con spreadsheets de google directamente. Me sabe mal por que te dije que me pondría pero aún no he hecho nada. Nuevamente, a la que tenga un momento, me pongo. sorry por la espera

      Eliminar
  8. Buenas, antes que nada felicidades por tu aporte esta muy bien definida la idea.

    tengo una duda como hago la decodificacion para agregar las contraseñas a la spreadsheet, tengo entendido que están en md5. pienso que el codigo fuinciona asi:

    *creo una spreadsheet con la url o simple en donde alojo mi code creo una nueva hoja.

    *agrego los campos requeridos (usuario, password y acceso).

    *agrego la información usuario y contraseña codificada para que el codigo la lea correctamente. esa parte es la que no se como la generaste

    ResponderEliminar
    Respuestas
    1. Lo generé con un script aparte.

      Sencillamente te montas un script cutre que te pille datos y te los "encripte" en md5. Se ha de hacer aparte de la web que estés haciendo o como una función dentro del código que solo llames desde el editor de código.

      Espero haberte servido de ayuda

      Nos vemos

      Pako

      Eliminar
    2. Si gracias amigo, pero ahora tengo un problema decodifique tus contraseñas para ver si corresponden con el siguiente código:

      var passwordMD5 = Utilities.base64Encode(Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, "password0"));
      Logger.log(passwordMD5);

      esta correcta pero cuando autentico con la contraseña y usuario correctos me manda el siguiente error google, tome tu codigo de referencia cambien la URL y el nombre del archivo html.

      400. That’s an error.

      The requested URL was not found on this server. That’s all we know.

      tal vez mi hoja sea la deje sin formato ni idea?, espero me puedas ayudar.

      Eliminar
  9. Keep calm, está controlado :D. Google hace un tiempo ( despues que yo hiciera este tutorial) cambió sus politicas de seguridad e hizo que este código no fuera "seguro" segun sus estandares. La solución es fácil.

    Desde el editor de código dale a crear nuevo fichero html, verás que aparece algo en el head referente a "top", copia ese trozo diferente en tu código.

    Deberia funcionar la magia a la que ejecutaras el código.

    Ya me explicarás como ha ido.

    Nos vemos

    Pako

    ResponderEliminar
    Respuestas
    1. gracias amigo no me a funcionado el base target="_top", persiste el error 400.. pero si al parecer es un problema como dices de seguridad, buscare en la pagina oficial. si te ha funcionado a ti, entonces no tengo idea que sea por que es el mismo codigo.

      saludos paku!..

      Eliminar
  10. Hola amigo, Muchas gracias por el post, Tengo un error me sale ERROR 400 The requested URL was not found on this server. That’s all we know.

    No tengo ni idea que puede ser el link del Spreadsheet, necesito permisos especiales para esto? Trabajo en una organización y tiene los permisos solo de compartir dentro de la organizacion.


    Agradezco tu ayuda.



    ResponderEliminar
    Respuestas
    1. Es un problema recurrente por un tema de cambio de política de google.

      Justo en el comentario anterior, "30 de enero de 2018, 19:01", puse la solución.

      Dime a ti como te ha ido.

      Gracias por leerme

      Pako

      Eliminar
  11. Hola... realice el cambio pero persiste el erro.

    Saludos

    ResponderEliminar
  12. Hola es muy interesante la utilización de GAS por lo que puedo ver, me hicieron el planteo de armar un formulario con Google Forms y guardar la información de los campos solicitados en Firebase Database, es posible ? de ser así alguna documentación ?. Gracias !!!

    ResponderEliminar
    Respuestas
    1. Hola Mauro,

      Desde Google Forms llenarás automaticamente un spreadsheet. Desde aqui te recomendaria un script que se ejecutara cada cierto tiempo y que importara la información del spreadsheet en Firebase. Para acceder a Firebase sino recuerdo mal, puedes hacerlo mediante FirebaseApp. Si tienes algun problema dimelo

      Nos vemos

      Eliminar
  13. Para que funcione tienes que saber la respuesta del código transformado MD5 y colocarlo en la base de datos, lo puedes hallar en logger.log:

    Logger.log('user:' + user + ' password:' + password +' passwordMD5:'+passwordMD5);


    cambia ademas el login a tipo reset en vez de submit

    ResponderEliminar
  14. Buenas tardes, excelente lo que has realizado , pero igual que los otros usuarios me apareces error 400, quisiera saber si se ha encontrado la solución , gracias

    ResponderEliminar
  15. Buena noche gracias por compartir este material y espero si puede responderme como amarrar varias páginas web de app agrio y a un inicio de sección me explico q yo me logueo entró a otra página web de app scrip y si esa página web de comparte ej por redes sociales al abrir lo redirecione al logro muchas gracias

    ResponderEliminar
  16. Hola, me encanta tu web para cuando quiero hacer mis pinitos, aunque soy un principiante total. Una pregunta, he hecho el script en un archivo GAS de mi GoogleDrive pero tengo mi blog en blogger en vez de en google.sites, es decir, no tengo el archivo index.html guardado en GoogleDrive. Quiero dar el acceso privado con login a una página stática dentro del blog, ¿qué tengo que cambiar del código? Supongo que el código HTML lo pegamos en la página estática en cuestión en blogger, pero en algún momento habrá q hacer referencia a la URL del script, no?. Otra cosa, una vez te logueas, ¿en qué URL aterriza el usuario logueado?.
    Muchas gracias, espero esto sirva a otras personas!

    ResponderEliminar
    Respuestas
    1. Hola buenas, me alegra que sirva de algo el blog.

      Lo que pides se puede hacer de diferentes maneras pero yo lo que haria seria poner el código dentro de un google site y hacer un iframe en tu blog del site.

      En todo momento la url será la misma, será el código del script el que se encargue de enseñar la información.

      Nos vemos

      Eliminar
  17. Hola,
    La verdad es que no he sabido hacer lo que dices. Al final lo he hecho enviando desde el html a través de ajax / jsonp, el usuario y la contraseña hacia el script de GAS y una vez ahí, comprueba en el googlesheet que usuario y clave coinciden siguiendo tu código. Si coinciden, el GAS envía la palabra "autorizado" al archivo html y éste te redirecciona hacia la url privada. Ahora mi duda es, si un usuario no logueado podría modificar el código de la web dándole a "inspeccionar" en el navegador, o peor aíun, si tiene la URL privada, podría introducirla en el navegador sin necesidad de loguearse! ¿Cómo podemos prevenirlo? Según veo aquí por ejemplo https://stackoverflow.com/questions/13621867/preventing-from-users-opening-other-pages-without-login es mediante una variable "sesión" en php. ¿Sabes dónde tengo que escribir este código en php? en el script de GAS no se puede escribir en PHP, y si lo escribo en el html, no es lado servidor sino lado cliente...¿Alguna idea?

    ResponderEliminar
    Respuestas
    1. Hola buenas,

      Te felicito, tienes un nivel de HTML nada desdeñable, pero, tienes algún lío de concepto con PHP y GAS.

      PHP es un lenguaje que genera HTML, igual que GAS. Esto quiere decir que ambos lenguajes no tienen nada que ver pero cumplen con roles parecidos. (script ejecutado en servidor)

      Ahora bien,PHP está orientado a la conexión y GAS al usuario.esto quiere decir que para PHP es fácil saber gracias a las cookies quien se está conectando y quien no y por lo tanto puede "capar" la conexión a una url privada con facilidad. GAS no lo tiene tan fácil.

      Es por ello q mi recomendación inicial era que la pagina privada la sirvieras directamente desde GAS. Con ello tienes el control total desde el script de lo que estas mostrando y dado que es la misma url la que hace el login que la que muestra la info siempre estarás seguro de hacer login antes de entrar en la zona privada.

      No se si me explicado muy bien :). Házmelo saber

      Nos vemos

      Eliminar
  18. Sí, te has explicado perfectamente. Lo que pasa es que no soy capaz de implementarlo. Yo tengo mi html que envía elusuario y contraseña mediante método GET de ajax y tipo de dato jsonp (que no sé ni qué significa, el caso es que funciona), y esto es recogido por la función doGet(e) en un archivo GAS publicado como aplicación web.
    El GAS tiene esta pinta:

    function doGet(e){

    "e" contiene el usuario y su clave recogidos del formulario html en la web.
    luego los comparo con el registro que tenemos en googlesheet, y si es coincide, la función devuelve la variable result, que es una cadena JSON que dice "Autorizado" o "No Autorizado". En particular, tras el bucle for que hace la comparación[...], el return es este:

    result = JSON.stringify({
    "result": result
    });
    return ContentService
    .createTextOutput(request.parameter.callback + "(" + result + ")")
    .setMimeType(ContentService.MimeType.JAVASCRIPT);

    realmente no tengo nivel, simplemente copio y pego cositas que veo en foros y tras muchas (de verdad muchas) horas, me acaba funcionando, pero no sé bien lo que hago. Tengo mucho cacao mental.
    Lo que tú dices es que en lugar de retornar este JSON, retorne lo siguiente:
    return HtmlService.createHtmlOutputFromFile('PaginaPrivada.html');
    siendo PáginaPrivada un archivo html que creo en el mismo editor de scripts de GoogleDrive, o bien una web externa http://blablabla.com , no?
    Lo he probado pero no me funciona... sabes qué estoy haciendo mal?

    Gracias de antemano

    ResponderEliminar
    Respuestas
    1. Buenas,

      Creo q casi lo tienes.

      return HtmlService.createHtmlOutputFromFile('PaginaPrivada.html');

      Es correcto pero en la parte del cliente deberias capturar ese html y renderizarlo, sino, se te quedará todo frito.

      Te recomiendo que vayas por trozos. No empiezes devolviendo todo un html, devuelve solo un string con algun html sencillito (" Cosas privadas y tal "). Cuando el GAS te devuelva el string deberas hacer que o bien el body del login o bien algun div en concreto reciban el html (mirate el innerHTML )

      Es algo complejillo pero lo q quieres no es facil.

      Nos vemos

      Eliminar
    2. Y cómo puedo capturarlo y renderizarlo?

      He puesto esto en el html cliente: (imagina que el símbolo - son los símbolos < > de los tags html, que por algún motivo no me deja tu blog escribirlos aquí):

      -div id="htmlprivado"-
      -/div-

      E igualmente en el html cliente, dentro de un -script-, en la función callback que se ejecuta cuando se recibe la respuesta del GAS, he puesto esto para caputarlo y asignarlo al div anterior y que se haga visible:

      $("#htmlprivado").html(e.result);
      $("#htmlprivado").css("visibility","visible");

      Supuestamente la e.result es el contenido del archivo html al que el GAS hace referencia... pero no hay manera,... no funciona.

      Te referías a esto con capturar el html y renderizarlo, o a otra cosa? es que no sale...

      Eliminar
    3. Hola.

      La gracia esta en que desde el login llames a una función del GAS y este te devuelva un html .

      Ese html en la función que se encarga de recibir la respuesta ha de hacer algo del estilo:

      function ProcesarRespuesta(respuesta)
      {
      document.getElementById("response").innerHTML = respuesta;
      }

      Tendras que mirar más tutoriales por que el tema tiene miga, pero la idea general es esa.

      Nos vemos

      Eliminar
  19. Hola Pako,

    Soy muy principiante...le he echado horas...pero no lo consigo. Esto de ser autodidacta sin ni siquiera hacer un curso baásico hace que me falten bases...

    Pero de repente tuve una idea...un poco rara pero que me ha funcionado!
    Como te decía, el GAS enviaba a blogger el string "autorizado" o "no autorizado". Como lo que decías no me salía, y lo del PHP era un lío total (blogger no acepta php por lo visto...), al final, en vez del string "autorizado", paso el código completo de la webPrivada que quiero mostrar como un string, simplemente metiéndolo entre comillas. Y luego ya en la página destino lo convierto de string a html, y así lo muestro en pantalla sin cambiar la url, que sigue siendo la misma que la del formulario de logueo. Y al formulario de logueo y todo lo que ya no quiero que salga en pantalla, le hago un hide() para que desaparezcan.

    Idea un poco estrambótica pero funciona. Además, todo ese código de la webPrivada, al estar dentro de una variable, creo que no se puede ver ni aunque inspecciones el código de la web de blogger. ¿me lo podrías confirmar? Dicho código sólo está en el el script de GAS de mi google Drive guardado como web app. Al código del GAS no puede tener nadie acceso tampoco, ¿no?

    Si me sabes confirmar estas dos preguntas, te lo agradezco, porque significaría que el problema está resuelto.

    Gracias en cualquier caso!

    ResponderEliminar
    Respuestas
    1. Hasta donde yo se, estas en lo correcto.

      De hecho, lo que has hecho es mas o menos lo que te había dicho de hacer (por un camino diferente, pero lo mismo al final y al cabo)

      Felicidades!

      Ya me irás contando como te va

      Eliminar
  20. nunca pude redireccionar despues de validar usuario, alguien me puede ayudar por favor. Gracias de antemano.

    ResponderEliminar
    Respuestas
    1. Redireccionar? Este login no está pensado para redireccionar sino para renderizar una web despues del login.

      Espero haberte sido de ayuda

      Eliminar
  21. Hola Pako.... Saludos desde Buenos Aires... me gustaria que me ayudaras a que luego de logearse, entrar a una pagina determinada, si el usuario y contraseña es correcta, entrar a una pagina que tambien esta publicada en drive... como hago? Gracias

    ResponderEliminar
    Respuestas
    1. Pues deberias de hacer el mismo proceso que utilizamos para servir el log pero para servir la web que quieres.

      Yo generalmente no sirvo webs de drive sino que las creo directamente desde el script, poco puedo ayudarte, pero la teoria es la misma que para hacer el log.

      Espero que te sirva

      Nos vemos

      Eliminar
    2. Lo que quiero es algo sencillo... Yo cree un "sitios de Google" donde hay cierta informacion, documentos y manuales... pero me gustaria que solo ciertos usuarios que solo yo debo registrar tengan acceso a ese "sitio de google" luego de logearse... ¿cual es el codigo que debo agregar al que tu publicastes para redireccionar?... por cierto.. agregue (base target="_top) al INdex.html y aun sigue apareciendo error 404...

      Eliminar
    3. Pues no te lo se decir, no es algo que use normalmente. A ver si alguna alma caritativa que lo haya hecho puede echarte un cable

      Nos vemos

      Eliminar
  22. bro no funciona el codigo da errores me encataria aprender pero no se :v

    ResponderEliminar
    Respuestas
    1. He implementado una nueva versión funcional del login en un solo fichero: https://googleappscriptsweb.blogspot.com/2019/10/como-hacer-un-login-con-google-apps.html

      Eliminar
  23. Para todos los que habeís tenido problemas de ejecución del login, podeís probar con este link: https://googleappscriptsweb.blogspot.com/2019/10/como-hacer-un-login-con-google-apps.html

    Es la versión revisada del login con Google Apps Scripts.

    Ya me comentareis como os va.

    ResponderEliminar
  24. Buen aporte, solo quisiera preguntar luego de montar el script como redireccionar a otra url

    ResponderEliminar
    Respuestas
    1. Te he respondido en el post más nuevo. Espero que te sirva

      Eliminar

Tal vez te interese