Utilizzo con il router finale
Con l'introduzione del nuovo router è diventato più facile sorvegliare le rotte. È necessario definire una guardia, che funge da servizio, e aggiungerla al percorso.
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { UserService } from '../../auth';
@Injectable()
export class LoggedInGuard implements CanActivate {
constructor(user: UserService) {
this._user = user;
}
canActivate() {
return this._user.isLoggedIn();
}
}
Ora passa LoggedInGuard
al percorso e aggiungilo anche providers
all'array del modulo.
import { LoginComponent } from './components/login.component';
import { HomeComponent } from './components/home.component';
import { LoggedInGuard } from './guards/loggedin.guard';
const routes = [
{ path: '', component: HomeComponent, canActivate: [LoggedInGuard] },
{ path: 'login', component: LoginComponent },
];
La dichiarazione del modulo:
@NgModule({
declarations: [AppComponent, HomeComponent, LoginComponent]
imports: [HttpModule, BrowserModule, RouterModule.forRoot(routes)],
providers: [UserService, LoggedInGuard],
bootstrap: [AppComponent]
})
class AppModule {}
Post di blog dettagliato su come funziona con la versione finale: https://medium.com/@blacksonic86/angular-2-authentication-revisited-611bf7373bf9
Utilizzo con il router deprecato
Una soluzione più robusta è quella di estendere RouterOutlet
e quando si attiva un percorso controllare se l'utente è loggato. In questo modo non è necessario copiare e incollare la direttiva su ogni componente. Inoltre, il reindirizzamento basato su un sottocomponente può essere fuorviante.
@Directive({
selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
publicRoutes: Array;
private parentRouter: Router;
private userService: UserService;
constructor(
_elementRef: ElementRef, _loader: DynamicComponentLoader,
_parentRouter: Router, @Attribute('name') nameAttr: string,
userService: UserService
) {
super(_elementRef, _loader, _parentRouter, nameAttr);
this.parentRouter = _parentRouter;
this.userService = userService;
this.publicRoutes = [
'', 'login', 'signup'
];
}
activate(instruction: ComponentInstruction) {
if (this._canActivate(instruction.urlPath)) {
return super.activate(instruction);
}
this.parentRouter.navigate(['Login']);
}
_canActivate(url) {
return this.publicRoutes.indexOf(url) !== -1 || this.userService.isLoggedIn()
}
}
La UserService
sta per il luogo in cui la logica di business risiede se l'utente è loggato o meno. Puoi aggiungerlo facilmente con DI nel costruttore.
Quando l'utente naviga verso un nuovo URL sul tuo sito web, il metodo di attivazione viene chiamato con l'istruzione corrente. Da esso puoi prendere l'URL e decidere se è consentito o meno. In caso contrario, reindirizza alla pagina di accesso.
Un'ultima cosa che resta per farlo funzionare, è passarlo al nostro componente principale invece che a quello integrato.
@Component({
selector: 'app',
directives: [LoggedInRouterOutlet],
template: template
})
@RouteConfig(...)
export class AppComponent { }
Questa soluzione non può essere utilizzata con il @CanActive
decoratore del ciclo di vita, perché se la funzione ad esso passata si risolve in false, il metodo di attivazione di RouterOutlet
non verrà chiamato.
Ha anche scritto un post dettagliato sul blog a riguardo: https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492