Je souhaite me connecter automatiquement à une page de connexion si l'utilisateur n'est pas connecté.
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { DashBoardComponent} from './dashboard/dashboard.component';
import { NotFoundComponent } from './not-found/not-found.component';
const APPROUTES: Routes = [
{path: 'home', component: AppComponent},
{path: 'login', component: LoginComponent},
{path: 'dashboard', component: DashboardComponent},
{path: '**', component: NotFoundComponent}
];
@NgModule({
declarations: [
AppComponent,
LoginComponent,
DashboardComponent
NotFoundComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
MaterialModule.forRoot(),
RouterModule.forRoot(APPROUTES)
],
providers: [],
bootstrap: [AppComponent]
})
Si l'utilisateur n'est pas connecté, le LoginComponent
devrait se charger, sinon le DashboardComponent
.
Voici 3 façons de faire ce que vous avez demandé, du moins préféré au préféré:
Option 1. Rediriger impérativement l'utilisateur dans AppComponent
@Component({
selector: 'app-root',
template: `...`
})
export class AppComponent {
constructor(authService: AuthService, router: Router) {
if (authService.isLoggedIn()) {
router.navigate(['dashboard']);
}
}
}
Pas très bien. Il est préférable de conserver les informations de "connexion requise" dans la déclaration de route à laquelle elles appartiennent.
Option 2. Utilisez un CanActivate
guard
Ajoutez un garde CanActivate
à tous les itinéraires qui nécessitent la connexion de l'utilisateur:
const APPROUTES: Routes = [
{path: 'home', component: AppComponent, canActivate:[LoginActivate]},
{path: 'dashboard', component: DashBoardComponent, canActivate:[LoginActivate]},
{path: 'login', component: LoginComponent},
{path: '**', component: NotFoundComponent}
];
Ma garde s'appelle LoginActivate
.
Pour que cela fonctionne, je dois ajouter la protection au providers
de mon module.
Et puis je dois le mettre en œuvre. Dans cet exemple, je vais utiliser la protection pour rediriger l'utilisateur s'il n'est pas connecté:
@Injectable()
export class LoginActivate implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean>|Promise<boolean>|boolean {
if (!this.authService.isLoggedIn()) {
this.router.navigate(['login']);
}
return true;
}
}
Consultez la documentation sur les gardes de route si cela n’a aucun sens: https://angular.io/docs/ts/latest/guide/router.html#guards
Cette option est meilleure mais pas super flexible. Que se passe-t-il si nous devons rechercher d'autres conditions que "connecté" telles que les autorisations des utilisateurs? Et si nous devions passer un paramètre à la garde, comme le nom d'un rôle "admin", "editor" ...?
Option 3. Utilisez la propriété route data
La meilleure solution à mon humble avis est d’ajouter des métadonnées dans la déclaration des routes pour indiquer "cette route nécessite que l’utilisateur soit connecté".
Nous pouvons utiliser la propriété route data
pour cela. Il peut contenir des données arbitraires et dans ce cas, j’ai choisi d’inclure un drapeau requiresLogin
qui est soit true
, soit false
(false
sera la valeur par défaut si n'est pas défini):
const APPROUTES: Routes = [
{path: 'home', component: AppComponent, data:{requiresLogin: true}},
{path: 'dashboard', component: DashBoardComponent, data:{requiresLogin: true}}
];
Maintenant, la propriété data
en elle-même ne fait rien. Mais je peux l'utiliser pour appliquer ma logique de "connexion requise". Pour cela, j'ai encore besoin d'un CanActivate
garde.
Dommage, vous dites. Maintenant, je dois ajouter 2 choses à chaque route protégée: les métadonnées ET la garde ...
MAIS:
CanActivate
garde à un itinéraire de niveau supérieur et il sera exécuté pour tous ses itinéraires enfants [À CONFIRMER]. De cette façon, vous ne devez utiliser la garde qu'une seule fois. Bien sûr, cela ne fonctionne que si les itinéraires à protéger sont tous des enfants d'un itinéraire parent (ce n'est pas le cas dans l'exemple de Rafael Moura).data
nous permet de transmettre toutes sortes de paramètres à la garde, par exemple. le nom d'un rôle spécifique ou de l'autorisation de vérification, un nombre de points ou de crédits que l'utilisateur doit posséder pour accéder à la page, etc.Compte tenu de ces remarques, il est préférable de renommer la garde en quelque chose de plus générique, comme AccessGuard
.
Je montrerai seulement le morceau de code où le garde récupère le data
attaché à la route, car ce que vous faites à l'intérieur du garde dépend vraiment de votre situation:
@Injectable()
export class AccessGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot): Observable<boolean>|Promise<boolean>|boolean {
const requiresLogin = route.data.requiresLogin || false;
if (requiresLogin) {
// Check that the user is logged in...
}
}
}
Pour que le code ci-dessus soit exécuté, vous devez suivre un itinéraire similaire à:
{
path: 'home',
component: AppComponent,
data: { requiresLogin: true },
canActivate: [ AccessGuard ]
}
NB N'oubliez pas d'ajouter AccessGuard
à votre providers
de votre module.
Vous pouvez aussi faire quelque chose comme ça:
{
path: 'home',
component: getHomeComponent(),
data: { requiresLogin: true },
canActivate: [ AccessGuard ]
}
Puis:
export function getHomeComponent(): Type<Component> {
if (User.isLoggedIn) {
return <Type<Component>>HomeComponent;
}
else{
return <Type<Component>>LoginComponent;
}
}