Użycie z końcowym routerem
Wraz z wprowadzeniem nowego routera ochrona tras stała się łatwiejsza. Musisz zdefiniować strażnika, który działa jako usługa, i dodać go do trasy.
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();
}
}
Teraz przekaż LoggedInGuardtrasę do trasy, a także dodaj ją do providerstablicy modułu.
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 },
];
Deklaracja modułu:
@NgModule({
declarations: [AppComponent, HomeComponent, LoginComponent]
imports: [HttpModule, BrowserModule, RouterModule.forRoot(routes)],
providers: [UserService, LoggedInGuard],
bootstrap: [AppComponent]
})
class AppModule {}
Szczegółowy post na blogu o tym, jak to działa z ostateczną wersją: https://medium.com/@blacksonic86/angular-2-authentication-revisited-611bf7373bf9
Użycie z przestarzałym routerem
Bardziej niezawodnym rozwiązaniem jest rozszerzenie RouterOutleti podczas aktywacji sprawdzania trasy, czy użytkownik jest zalogowany. W ten sposób nie musisz kopiować i wklejać dyrektywy do każdego komponentu. Ponadto przekierowania oparte na składniku podrzędnym mogą wprowadzać w błąd.
@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()
}
}
Plik UserServiceStoi w miejscu, gdzie mieszka twoja logika biznesowa, czy użytkownik jest zalogowany czy nie. Możesz go łatwo dodać za pomocą DI w konstruktorze.
Gdy użytkownik przejdzie do nowego adresu URL w Twojej witrynie, metoda aktywacji jest wywoływana z aktualną instrukcją. Z niego możesz pobrać adres URL i zdecydować, czy jest to dozwolone, czy nie. Jeśli nie, po prostu przekieruj do strony logowania.
Ostatnią rzeczą, która pozostała, aby to zadziałało, jest przekazanie go do naszego głównego komponentu zamiast do wbudowanego.
@Component({
selector: 'app',
directives: [LoggedInRouterOutlet],
template: template
})
@RouteConfig(...)
export class AppComponent { }
Tego rozwiązania nie można używać z @CanActivedekoratorem cyklu życia, ponieważ jeśli przekazana do niego funkcja rozwiąże wartość false, metoda aktywacji elementuRouterOutlet nie zostanie wywołana.
Napisałem również na ten temat szczegółowy post na blogu: https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492