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ż LoggedInGuard
trasę do trasy, a także dodaj ją do providers
tablicy 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 RouterOutlet
i 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 UserService
Stoi 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 @CanActive
dekoratorem 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