Uso con el enrutador final
Con la introducción del nuevo enrutador se hizo más fácil proteger las rutas. Debe definir un guardia, que actúa como un servicio, y agregarlo a la ruta.
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();
}
}
Ahora pase el LoggedInGuarda la ruta y también agréguelo a la providersmatriz del módulo.
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 declaración del módulo:
@NgModule({
declarations: [AppComponent, HomeComponent, LoginComponent]
imports: [HttpModule, BrowserModule, RouterModule.forRoot(routes)],
providers: [UserService, LoggedInGuard],
bootstrap: [AppComponent]
})
class AppModule {}
Publicación de blog detallada sobre cómo funciona con la versión final: https://medium.com/@blacksonic86/angular-2-authentication-revisited-611bf7373bf9
Uso con el enrutador obsoleto
Una solución más sólida es extender el RouterOutlety al activar una ruta, verifique si el usuario está conectado. De esta manera, no tiene que copiar y pegar su directiva en cada componente. Además, la redirección basada en un subcomponente puede ser engañosa.
@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()
}
}
los UserService representa el lugar donde reside la lógica de negocio si el usuario está conectado o no. Puede agregarlo fácilmente con DI en el constructor.
Cuando el usuario navega a una nueva URL en su sitio web, se llama al método de activación con la instrucción actual. Desde allí, puede tomar la URL y decidir si está permitida o no. Si no, simplemente redirija a la página de inicio de sesión.
Una última cosa que queda para que funcione, es pasarlo a nuestro componente principal en lugar del integrado.
@Component({
selector: 'app',
directives: [LoggedInRouterOutlet],
template: template
})
@RouteConfig(...)
export class AppComponent { }
Esta solución no se puede utilizar con el @CanActivedecorador de ciclo de vida, porque si la función que se le pasa se resuelve como falso, el método de activación delRouterOutlet no se llamará al .
También escribí una publicación de blog detallada al respecto: https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492