Desarrollar Webapps Realtime: Auth
Código en GitHub: building-realtime-webapp. Release: auth
.
Entorno de desarrollo en Heroku: building-realtime-webapp.
Siguiendo con la saga de “Desarrollar Webapps Realtime” y depués de haber visto Cómo empezar a crear un Webapp real-time y cómo crear usuarios siguiendo el patrón MVC, le toca el turno a cómo autenticar a los usuarios en nuestra plataforma. Para ello vamos a hacerlo primero con nuestros propios medios para entender algunos conceptos y después lo haremos usando Passport for Node.
Cambios en el layout
Lo primero que vamos a hacer es cambiar la barra de navegación añadiendo el botón de login cuando el usuario no esté autenticado y su correo y el boton de logout cuando si lo esté. Para ello debemos comprobar la variable session.authenticated
que estableceremos en el controlador. Estas líneas las añadimos después de nuestro menú de navegación, <ul class="nav navbar-nav">[…]</ul>
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Si os fijáis para crear un nuevo usuario y para la página de autenticación he usado enlaces pero para el log out he usado un formulario con un botón. Esto es porque en los enlaces se utilizan para navegar y los botones para acciones.
Autenticación básica
Para gestionar las sesiones necesitaremos las acciones auth
, login
y logout
. Estas acciones las vamos a añadir en UserController
, aunque podrían ir en un nuevo controlador llamado SessionController
. Como posteriormente vamos a implementar la autenticación con Passport lo moveremos a un controlador especifico llamado AuthController
.
Acción auth
Esta acción simplemente nos devolverá una vista con el formulario de autenticación. Así que habrá que crear la vista /view/user/auth.ejs
en la que le solicitaremos el email y la contraseña. Esta vista es muy similar a /view/user/new.ejs
, así que podemos copiar y pegar el contenido y hacemos un par de cambios:
- El action del from ya no es
/user/create
sino/user/login
. - Los 3 textos (migas de pan, título y botón) donde pone ‘Create user’ ponemos ‘Auth user’.
Y en el controlador copiamos la acción new sin hacer ningún cambio.
1 2 3 |
|
Ahora podemos lanzar el servidor y comprobar que la url http://localhost:1337/user/auth funciona correctamente.
Acción Login
En esta acción hay un poco más de chicha, ya que tendremos que buscar el usuario mediante el email, comparar la contraseña y guardar una variable de sessión.
1 2 3 4 5 6 7 8 9 10 11 |
|
Si lanzamos el servidor de nuevo y probamos a rellenar el formulario con uno de los usuarios previamente creados, vemos como nos redirecciona a la página del usuario y nos reemplaza los botones de ‘Ingresar’ y ‘Resistrarse’ por el email del usuario y un botón de ‘Desconectar’.
Tenemos que tener en cuenta que cunado se crea un usuario podemos considerarlo autenticado. O bien esperar a que verifique su mail, pero como de momento no enviamos mail. Consideraremos al usuario autenticado al crear la nueva cuenta, asignando los valores a la sesión antes de enviar la respuesta:
1 2 3 4 5 6 7 8 |
|
Acción Logout
En este caso, es mucho más facil, simplemente destruimos la sesión y redirigimos al usuario a la home.
1 2 3 4 |
|
Volvemos a lanzar el servidor, hacemos login y una vez en la página del usuario pulsamos el botón de ‘Desconectar’ para ver como salimos de la sessión y vuelven a aparecer los botones de ‘Ingresar’ y ‘Resistrarse’.
Commit en GitHub: 01e14ef420: Authentication on UserController: auth, login and logout actions.
Políticas de acceso
Recomiendo echarle un ojo a la Documentación de Sails sobre Políticas.
Autenticar a un usuario tiene la misión principal de conceder o denegar el acceso a algunas partes de nuestra aplicación. Para ello haremos uso de las políticas (policies). Estas políticas las declaramos en el directorio /api/policies
.
Política usuario autenticado
Por defecto Sails nos incluye la política isAuthenticated.js
. La cual hace uso de la variable de sessión que establecemos a true
cuando el usuario se identifica. Una politica se declara como un módudo y ejecuta la función de callbac next
cunado se concede acceso o devuelve forbidden en caso contrario.
1 2 3 4 5 |
|
Ahora que tenemos la políca definida debemos aplicarla a alguna URL o acción del controlador. Para ello accedemos a /config/policies.js
donde definiremos las políticas que se aplcian en cada caso.
1 2 3 4 5 6 7 8 9 10 11 |
|
Con esto estamos permitiendo el acceso a todas las acciones del UserController
, y en algunos casos (find, update, destroy, edit, logut), le pedimos que estén autenticados. Personalmente prefiero aplicar las políticas partiendo de la restricción, es decir, para todas las acciones hay que estar autenticado salvo para las que definamos como abiertas. Quedaría de esta manera:
1 2 3 4 5 6 7 8 9 10 |
|
En ambos casos permitimos el acceso a las mismas url, pero si añadimos una acción al controlador, estará protegida por defecto.
Commit en GitHub: e58ea71cc3: isAuthenticated policy.
Política de poder Administar usuario
Para los casos de editar y eliminar, debemos asegurarnos de que el usuario es él mismo, para evitar que un usuario pueda editar o eliminar cuentas que no son la suya. Más adelante podremos establecer perfiles administradores que también puedan realizar esas acciones, por eso vamos a llamar a la política canAdminUser
:
1 2 3 4 5 |
|
Además tendremos que actualizar nuestras políticas:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Ahora si intentamos editar o eliminar un usuario no podremos. Así que deberíamos quitar los botones de la interfaz de usuario para reducir la generación de errores. Por lo que añadimos este condicional para mostrar las opciones sólo en caso necesario.
1 2 3 4 5 6 7 8 |
|
Una solución más elegante para no tener que aplicar esta lógica en la template sería utilizar la variable session.canAdminUser. Una forma más elegante, que delega la responsibilidad de la lógica al controlador, que es quien lo debe hacer.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
De esta forma si cambiamos las políticas de acceso a la página de listado de usuarios nos aseguramos que solo verán las acciones editar y eliminar aquellos que puedan ejecutarlas.
Commit en GitHub: 01a7287d07: Can Admin User Policy.
Código en GitHub: building-realtime-webapp. Release: auth
.
Entorno de desarrollo en Heroku: building-realtime-webapp.