Avanzado #2 Autenticaci贸n b谩sica Angular.io con Auth0 馃敀

Cuando creamos una aplicaci贸n una de las partes m谩s importantes es la autenticaci贸n dado que deseamos que sea segura y podamos proteger los datos de los usuarios, aprendamos juntos como hacerlo 馃攼

馃挕 Introducci贸n 馃挕

En este desaf铆o vamos a aprender a tener una autenticaci贸n con Auth0 y las ventajas de usarla. En un mundo donde casi [email protected] usan la misma contrase帽a para todo, la fecha de su cumplea帽os, el nombre de su mascota, entre otras malas pr谩cticas para protecci贸n de datos, te est谩s asegurando de cuidar la informaci贸n de manera simple. 馃攼

隆Aqu铆 puedes encontrar un demo!

Paso 1: Creemos nuestra App de Angular 馃叞锔

Entra a www.stackblitz.com, y ver谩s algo como esto:

Paso 2: Vamos a crear una cuenta en Auth0

Esta cuenta es totalmente gratuita, Auth0 se encargar谩 de la autenticaci贸n de los usuarios por nosotros, ellos tienen unos servicios, llamados API donde t煤 los llamas y seg煤n la informaci贸n que le env铆es 茅l te responder谩 si es el usuario correcto, tambi茅n nos realizar谩 procesos de autenticaci贸n de terceros como Google o recordar contrase帽a, se asegurar谩 que no sea un correo maligno que le este haciendo peticiones cuando intenta recordar la contrase帽a y que no est谩n tratando de atacar tu aplicaci贸n, asiendo as铆, un inicio de sesi贸n muy seguro. Entra a https://auth0.com/, y crearas una cuenta as铆:

Podr谩s crear una cuenta con un usuario y contrase帽a o con una cuenta que ya tengas anteriormente por un tercero. Yo usar茅 la de Google para este ejemplo.

Cuando ya ingreses a tu cuenta, podr谩s ver una plataforma de manejo de tus aplicaciones e inicios de sesi贸n en ella, puedes sacar estad铆sticas, hacer grupos por roles y permisos, decir a que usuario les va a otorgar ciertos accesos y a cuales no. 隆Y mucho m谩s!

Al darle click en + Create Application creamos una nueva instancia para manejar el inicio de sesi贸n de nuestra aplicaci贸n. Y seleccionamos Single Page Web Application como el tipo de autenticaci贸n que vamos a usar.

Curando ya tengamos nuestra nueva instancia, Auth0 nos va a proveer de un client ID que usaremos para todos los llamados a su API.

Vamos a tomar la URL de nuestra aplicaci贸n que nos genera https://stackblitz.com/ y vamos a usarla para que Auth0 sepa que cuando hagamos un llamado a su API desde nuestra aplicaci贸n, nos responda con la configuraci贸n que esperamos al respecto.

Esta es la ubicaci贸n de la URL de nuestra aplicaci贸n en https://stackblitz.com/ Guarda los cambios y estas listo para usarla.

Paso 3: Vamos insertar la funcionalidad para hacer llamados a funcionalidades externas como una API y adicionaremos router.

Ya aprendiste como adicionar router, ahora vamos a adicionar la funcionalidad HTTP Client Module en nuestro app.module.ts y luego hacemos su llamado a desde imports

import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';

Paso 4: Adicionar las variables de configuraci贸n

En este archivo vamos a sacar las variables necesarias para manejar nuestra aplicaci贸n, esta va a ser la informaci贸n que le entregaremos a la API de Auth0 y con ella nos identificaremos. vamos a crear un archivo llamado donde las pondremos auth0-variables.ts

auth0-variables.ts
interface AuthConfig {
clientID: string;
domain: string;
audience: string;
redirectUri: string;
}
export const AUTH_CONFIG: AuthConfig = {
clientID: '',// TODO: '<YOUR_AUTH0_CLIENT_ID>'
domain: '', // TODO '<YOUR_AUTH0_DOMAIN>'
audience: '', // TODO: https://<YOUR_AUTH0_DOMAIN>/userinfo
redirectUri: "https://angular-basic-with-auth0.stackblitz.io/callback",
};

No olvides, que cuando termines el ejercicio debes borrar esas variables, para que personas en internet no usen tu cuenta sin tu autorizaci贸n o roben tu informaci贸n.

Paso 5: Crea un servicio de autenticaci贸n

La mejor manera de administrar y coordinar las tareas necesarias para la autenticaci贸n del usuario es crear un servicio reutilizable. Con el servicio en su lugar, podr谩 llamar a sus m茅todos a trav茅s de su aplicaci贸n. Se puede crear una instancia del objeto WebAuth de auth0.js en el servicio AuthService.ts.

AuthService.ts
import { Injectable } from "@angular/core";
import * as auth0 from "auth0-js";
import { environment } from "../../environments/environment";
import { Router } from "@angular/router";
(window as any).global = window;
@Injectable()
export class AuthService {
auth0 = new auth0.WebAuth({
// the following three lines MUST be updated
domain: environment.domain, // TODO '<YOUR_AUTH0_DOMAIN>'
audience: environment.audience, // TODO: https://<YOUR_AUTH0_DOMAIN>/userinfo
clientID: environment.clientID, // TODO: '<YOUR_AUTH0_CLIENT_ID>'
redirectUri: environment.redirectUri,
responseType: "token",
scope: "openid profile"
});
// Store authentication data
expiresAt: number;
userProfile: any;
accessToken: string;
authenticated: boolean;
constructor(private router: Router) {
this.getAccessToken();
}
login() {
// Auth0 authorize request
this.auth0.authorize();
}
handleLoginCallback() {
// When Auth0 hash parsed, get profile
this.auth0.parseHash((err, authResult) => {
if (authResult && authResult.accessToken) {
window.location.hash = '';
this.getUserInfo(authResult);
} else if (err) {
console.error(`Error: ${err.error}`);
}
this.router.navigate(['/']);
});
}
getAccessToken() {
this.auth0.checkSession({}, (err, authResult) => {
if (authResult && authResult.accessToken) {
this.getUserInfo(authResult);
}
});
}
getUserInfo(authResult) {
// Use access token to retrieve user's profile and set session
this.auth0.client.userInfo(authResult.accessToken, (err, profile) => {
if (profile) {
this._setSession(authResult, profile);
}
});
}
private _setSession(authResult, profile) {
// Save authentication data and update login status subject
this.expiresAt = authResult.expiresIn * 1000 + Date.now();
this.accessToken = authResult.accessToken;
this.userProfile = profile;
this.authenticated = true;
}
logout() {
// Log out of Auth0 session
// Ensure that returnTo URL is specified in Auth0
// Application settings for Allowed Logout URLs
this.auth0.logout({
returnTo: 'http://localhost:4200',
clientID: environment.auth.clientID
});
}
get isLoggedIn(): boolean {
// Check if current date is before token
// expiration and user is signed in locally
return (Date.now() < this.expiresAt) && this.authenticated;
}
}

Por si tienes alguna duda. Aqu铆 te explicamos c贸mo funciona: 馃懛鈥嶁檧锔 1. En auth0.WebAuth( estamos asignando las variables de configuraci贸n que creamos en el paso anterior. 2. El servicio incluye varios m茅todos para manejar la autenticaci贸n. login: las llamadas autorizan desde auth0.js que inicia el inicio de sesi贸n universal. handleAuthentication: busca un resultado de autenticaci贸n en el hash de URL y lo procesa con el m茅todo parseHash de auth0.js. setSession: establece el token de acceso del usuario, el token de identificaci贸n y la hora en que caducar谩 el token de acceso cerrar sesi贸n: elimina los tokens del usuario del almacenamiento del navegador. isAuthenticated: verifica s铆 el tiempo de vencimiento del token de acceso ha pasado.

Paso 6: Crea una clase que nos manejar谩 el callback

Para manejar la ruta de devoluci贸n de llamada (https://angular-basic-with-auth0.stackblitz.io/callback), vamos a definir un componente que se encargar谩 solo de esto, crea un nuevo archivo llamado callback.component.ts dentro del directorio app e inserta el siguiente c贸digo:

callback.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthService } from './auth/auth.service';
@Component({
selector: 'app-callback',
template: `
<p>
Loading...
</p>
`,
styles: []
})
export class CallbackComponent implements OnInit {
constructor(private auth: AuthService) { }
ngOnInit() {
this.auth.handleLoginCallback();
}
}

Paso 7: Vamos a crear el routing model de nuestra aplicaci贸n

Para manejar la ruta de desde nuestra a aplicaci贸n al inicio de sesi贸n universal solo necesitamos crear un app-routing.module.ts que nos controlar谩 cada vez que vayamos a autenticarnos y volvamos a nuestra aplicaci贸n:

app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CallbackComponent } from './callback.component';
import { AuthGuard } from './auth/auth.guard';
const routes: Routes = [
{
path: '',
redirectTo: '',
pathMatch: ''
},
{
path: 'callback',
component: CallbackComponent
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
providers: [AuthGuard],
exports: [RouterModule]
})
export class AppRoutingModule { }

Para manejar complementar el manejo de la ruta usaremos esta clase AuthGuard auth.guard.ts nos ayudar谩 a manejar la ruta de autenticaci贸n:

auth.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
import { Router } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router
) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (!this.authService.isLoggedIn) {
this.router.navigate(['/']);
return false;
}
return true;
}
}

Paso 8: Vamos a terminar de configurar nuestro app.module.ts

Acabamos de crear CallbackComponent y AuthService vamos a incluirlos tambi茅n. en el app.module.ts

import { CallbackComponent } from './callback.component';
import { AuthService } from './auth/auth.service';

Paso 9: Vamos a poner el login en la interfaz de nuestra aplicaci贸n

Usaremos la siguiente l贸gica para llamar al m茅todo de autenticaci贸n y as铆 determinar si debemos mostrar un elemento de IU espec铆fico o no. Como ejemplo, solo queremos mostrar el enlace de Log In si no est谩 autenticado, y Log Out si no est谩 autenticado. En el archivo app.component.html pondremos lo siguiente:

app.component.html
<ul class="nav navbar-nav navbar-right">
<li>
<a *ngIf="!authService.isLoggedIn" (click)="authService.login()">Log In</a>
</li>
<li>
<a (click)="authService.logout()" *ngIf="authService.isLoggedIn">Log Out</a>
</li>
</ul>

En el archivo app.component.ts pondremos lo siguiente:

app.component.ts
import { AuthService } from './auth/auth.service';
constructor(public authService: AuthService) {}

Nos daremos cuenta que el mismo stackblitz se da cuenta que nos hace falta instalar un paquete y nos pide que instalemos el de Auth0.js y damos clic en install package

LO LOGRASTE! 馃帀

Aqu铆 puedes encontrar el ejercicio resuelto.

馃槑 Tu Misi贸n 馃槑

Con lo que aprendiste en el ejercicio de hoy, crea un inicio de sesi贸n con personalidad, 隆ponle estilo!

La primer chica en mostrarme que termino este ejercicio se gana autom谩ticamente una camiseta de Auth0 馃帀

Has completado este desaf铆o y finalizado con todos los desaf铆os del taller 隆隆Felicitaciones!! 馃帀馃帀馃帀

Nota:

Si necesitas ayuda con este ejercicio puedes contactar a:

Alejandra Giraldo Twitter: @maleja111 Correo: [email protected]

No olvides este super importante paso Clic eliminar las variables de Auth0