Logowanie do aplikacji
Auth0 przygotowało bibliotekę js ułatwiającą korzystanie z tego serwisu, wykorzystanie jej co prawda zacieśnia zależność od dostawcy, zmniejsza jednak ilość pracy do wykonania. Można ją zainstalować przy pomocy narzędzia npm. Oprócz samej biblioteki zainstalowałem także definicję typów dla niej.
npm install --save auth0-js npm install --save @types/auth0-js
Aby ograniczyć powtórzenia w kodzie oraz wpływ biblioteki na resztę aplikacji stworzyłem klasę AuthService. Na początek dodałem do niej tylko metodę login.
export class AuthService { public login() : void { } }
Biblioteka auth0-js zawiera klasę WebAuth, której konstruktor jako parametr przyjmuje obiekt zawierający konfigurację klienta, należy w niej uzupełnić pola:
- domain – domena w auth0 odpowiadająca tej aplikacji
- clientID – identyfikator aplikacji
- responseType – typ odpowiedzi – może zawierać wiele wartości mi zależało tylko na tokenie
- redirectUri – strona na którą użytkownik zostanie przekierowany po udanym logowaniu
- audience – wartość pobrana z API z którym aplikacja chce się komunikować
Klasa WebAuth zawiera też metodę authorize otwierającą ekran logowania.
Należy też podać adres pod który użytkownik zostanie przeniesiony po udanym logowaniu oraz typ odpowiedzi. Można to zrobić przez parametr konstruktora klasy WebAuth albo przez parametr metody authorize.
import {WebAuth} from 'auth0-js'; export class AuthService { private webAuth: WebAuth; constructor() { this.webAuth = new WebAuth({ domain: 'rocket-launcher.eu.auth0.com', clientID: 'a-a2L8phemO9HGh4J6M9xnDaIg7Yw8fH', responseType: 'token', redirectUri: 'http://localhost:8080/logged-in', audience: 'http://rocket-service.com' }); } public login() : void { this.webAuth.authorize({}); } }
Wywołanie metody dodałem do metody login w klasie Home, wykorzystałem przy okazji wbudowany w Aurelię kontener IoC.
import {inject} from 'aurelia-framework'; import {AuthService} from './auth-service'; @inject(AuthService) export class Home { private authService : AuthService; constructor(authService: AuthService) { this.authService = authService; } public login() : void { this.authService.login(); } }
Wywołanie tej metody powiązałem z przyciskiem na widoku.
Na tym etapie po kliknięciu w przycisk „Login” użytkownik zostaje przekierowany do ekranu logowania/rejestracji. Po rejestracji użytkownik przechodzi do strony Logged In
Adres strony zawiera dane autoryzacyjne, do ich rozkodowania i weryfikacji biblioteka dostarcza metodę parseHash. Otoczyłem tą metodę metodą checkHash w klasie AuthService, metoda wykorzystuje klasę Promise, która zwraca rezultat jeżeli uda się zinterpretować hash.
public checkHash(): Promise{ return new Promise((resolve, reject) => { this.webAuth.parseHash((error, result) => { if (error && error.errorDescription) { reject(error.errorDescription); return; } if (result && result.accessToken && result.idToken) { resolve(); return; } reject('Bad request'); }) }); }
Metodę tą wywołuję z metody activate w klasie LoggedIn
public activate() { this .authService .checkHash() .then( () => this.router.navigateToRoute('launch-console'), error => this.message = error); }
Metoda activate jest wywoływana na view-modelu dla tuż przed podpięciem go do widoku. Jeżeli metoda potwierdzi że weryfikacja się udała użytkownik zostaje przekierowany do konsoli odpalenia pocisków. W przeciwnym wypadku zostaje ustawiona właściwość messege widoczna jako komunikat błędu. Aby uzyskać dostęp do obiektu router i authService wykorzystałem dekorator inject
import {inject} from 'aurelia-framework'; import {AuthService} from './auth-service'; import {Router} from 'aurelia-router'; @inject(AuthService, Router) export class LoggedIn { private authService: AuthService; private router: Router; public message: string; constructor( authService: AuthService, router: Router){ this.authService = authService; this.router = router; this.message = "Please wait"; } ... }
Wylogowanie się z aplikacji
W obecnym stanie aplikacja nie posiada mechanizmu wylogowania. Niestety zamknięcie zakładki nie jest wystarczającym zabezpieczeniem, ponieważ po kliknięciu przycisku „Login” Auth0 dostarcza dane token bez pytania o login i hasło. Obiekt webAuth posiada metodę logout, którą wystarczy po prostu wywołać.
Podobnie jak w przypadku metody login utworzyłem metodę logout w klasie AuthManager.
public logout(): void { this.webAuth.logout({ returnTo: 'http://localhost:8080/logged-out' }); }
Parametr return to wskazuje adres na który trafi użytkownik po udanym wylogowaniu. Wywołanie tej metody dodałem do klasy LaunchConsole, podobnie jak w przypadku logowania dodałem także przycisk uruchamiający tą metodę.
import {inject} from 'aurelia-framework'; import {AuthService} from './auth-service'; @inject(AuthService) export class LaunchConsole { private authService: AuthService; constructor(authService: AuthService) { this.authService = authService; } public logout() { this.authService.logout(); } }
Ostatnim krokiem było dodanie ciała do klasy LoggedOut. Dodałem tam tylko przekierowanie do głównego ekranu aplikacji w celu usunięcia parametrów z adresu.
import {inject} from 'aurelia-framework'; import {Router} from 'aurelia-router'; @inject(Router) export class LoggedOut { private router: Router; constructor(router: Router) { this.router = router; } public activate() { this.router.navigateToRoute('home'); } }
Jedna odpowiedź do “Auth-0 aplikacja do odpalania rakiet – frontend”