Le Guide Angular | Marmicode
  • Le Guide Angular par Marmicode
  • Pourquoi Angular ?
  • ECMAScript 6+
    • Un Peu d'Histoire
    • Propriétés du Langage
    • "Single-Threaded" donc Asynchrone
    • Event Loop
    • Classes
    • Hoisting is Dead: var vs. let vs. const
    • this & "binding"
    • Arrow Functions
    • Template Strings
    • Syntactic Sugar
      • Spread
      • Destructuring
      • Rest
      • Object Literal Property Value Shorthand
    • Named Parameters
    • Compatibilité
  • TypeScript
    • Pourquoi TypeScript ?
    • De l'ECMAScript au TypeScript
    • Visibilité des Propriétés
    • Typing des Propriétés
    • Types
    • Interfaces
    • Inference
    • Duck Typing
    • Duck Typing Patterns
      • Compatibilité de Librairies
      • Entity Constructor
    • Décorateurs
      • Décorateurs de Propriété
      • Décorateurs de Classe
      • Décorateurs de Méthode & Paramètres
    • Quelques Liens
  • Tools
    • Clavier mécanique
    • Git
    • Command Line
    • NodeJS
    • NPM
    • Yarn
      • Pourquoi Yarn ?
      • Définition et Installation des Dépendances
      • Scripts
      • Mise à Jour et Automatisation
    • Chrome
    • IntelliJ / WebStorm / VSCode
      • Raccourcis clavier IntelliJ / WebStorm
    • Floobits
    • Angular CLI
    • StackBlitz
    • Compodoc
  • Angular
    • Bootstrap
    • Composants
      • Root Component
      • Template Interpolation
      • Property Binding
      • Class & Style Binding
      • Event Binding
      • *ngIf
      • *ngFor
      • L'approche MVC
      • Création de Composants
      • Exemple
    • Container vs. Presentational Components
    • Interaction entre Composants
      • Input
      • Output
      • Exemple
    • Change Detection
      • Les Approches Possibles
      • Fonctionnement de la Change Detection
      • Optimisation de la Change Detection
      • Immutabilité
      • Quelques Liens
    • Project Structure & Modules
      • Entry Point
      • Définition d'un Module
      • Root Module
      • Feature Module
      • Shared Module
      • Exemple
    • Dependency Injection
      • Qu'est-ce que la "Dependency Injection" ?
      • Injection d'un Service Angular
      • Services & Providers
      • Portée des Services
      • Tree-Shakable Services
      • Class vs Injection Token
      • Exemple
    • Callback Hell vs. Promise vs. Async / Await
      • Callback Hell
      • Promise
      • Async / Await
    • Observables
      • Reactive Programming
      • Promise vs Observable
      • Subscribe
      • Unsubscribe ⚠️
      • Création d'un Observable
      • Opérateurs
        • Définition d'un Opérateur
        • Lettable Operators vs Legacy Methods
        • map
        • filter
        • mergeMap & switchMap
        • shareReplay
        • buffer
        • debounceTime
        • distinctUntilChanged
        • retry
      • Quelques Liens
      • Talks
    • Http
      • Pourquoi HttpClient ?
      • Utilisation de HttpClient
      • Utilisation dans un Service
      • Gestion de la Subscription ⚠️
    • State Management
      • Quelques Liens
      • Talks
    • GraphQL
    • Formulaires
      • Template-driven Forms 🤢
      • Reactive Forms 👍
        • Avantages des "Reactive Forms"
        • La boite à outils des "Reactive Forms"
        • Validation
        • Observation des Changements
    • Directives
      • Attribute Directive
      • Structural Directive
    • Pipes
    • Routing
      • Mise en Place du Routing
      • Lazy Loading
      • Project Structure
      • Route Guards
    • Testing
      • Unit-Testing
        • 📺Introduction au Test-Driven Development
        • Jasmine
        • Unit-Test Synchrone
        • Test-Driven Development
        • Unit-Test Asynchrone
        • TestBed
        • Unit-Test d'un Service
        • Unit-Test d'un Composant
        • Unit-Test et Spies
        • Unit-Test et HttpClient
      • End-to-End
      • Talks
    • Sécurité
      • Quelques Liens
    • Animation
    • Internationalisation
    • Quelques Liens
  • Cookbook
    • Authentification et Autorisation
    • Remplacement Dynamique de Composants
    • Lazy Loading without Router
    • Project Structure
    • SCAM Modules
    • Setup a Mock ReSTful API
  • Autres Ressources
  • Stay Tuned
    • 🎁-20% sur nos workshops avec le code GUIDEANGULAR
    • 🐦Suivez-moi !
    • 📺Cours Vidéo
    • 📬Newsletter
    • 📝Blog
  • Nos Services
    • Formation Angular
    • Atelier Unit-Testing Angular
    • Atelier Architecture Angular
    • Consultation à Distance & Code Review
  • Nos Guides
    • Guide Agile
    • Guide API ReST
    • Guide NodeJS
Propulsé par GitBook
Sur cette page
  • Configuration
  • CanActivate
  • CanDeactivate
  1. Angular
  2. Routing

Route Guards

PrécédentProject StructureSuivantTesting

Dernière mise à jour il y a 5 ans

Les "Guards" permettent de contrôler l'accès à une "route" (e.g. autorisation) ou le départ depuis une "route" (e.g. enregistrement ou publication obligatoire avant départ).

Les "Guards" ne doivent en aucun cas être considérés comme un mécanisme de sécurité.

La gestion de permission des accès aux ressources doit se faire au niveau des APIs HTTP : .

Les "Guards" servent à améliorer la "User eXperience" en évitant par exemple l'accès à des "routes" qui ne fonctionneraient pas car l'accès aux données serait rejeté par l'API.

Configuration

Les "Guards" sont ajoutés au niveau de la configuration du "Routing" :

export const appRouteList = [
    {
        path: 'cart',
        loadChildren: './views/cart/cart-routing.module#CartRoutingModule',
        canActivate: [
            IsSignedInGuard
        ]
    },
    {
        path: 'signin',
        component: SigninViewComponent,
        canActivate: [
            IsNotSignedInGuard
        ]
    },
    {
        path: 'profile',
        component: ProfileViewComponent,
        canDeactivate: [
            IsNotDirtyGuard
        ]
    }
]

CanActivate

Une "Guard" d'activation est un service qui implémente l'interface CanActivate.

Ce service doit donc implémenter la méthode canActivate. Cette méthode est appelée à chaque demande d'accès à la "route" ; elle doit alors retourner une valeur de type boolean ou Promise<boolean> ou Observable<boolean> indiquant si l'accès à la "route" est autorisé ou non.

Il est donc possible d'attendre le résultat d'un traitement asynchrone pour décider d'autoriser l'accès ou non.

@Injectable({
    providedIn: 'root'
})
export class IsSignedInGuard implements CanActivate {

    constructor(private _session: Session) {
    }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        return this._session.isSignedIn();
    }

}

En cas de refus d'accès, il est possible de rediriger l'utilisateur vers une autre "route" "manuellement" en injectant le service "Router" par exemple :

    constructor(private _router: Router,
                private _session: Session) {
    }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {

        const isSignedIn = this._session.isSignedIn();

        if (isSignedIn !== true) {
            this._router.navigate([...]);
        }

        return isSignedIn;

    }

CanDeactivate

Les "Guards" de désactivation sont couplées aux composants car elles doivent communiquer avec le composant pour établir leur décision d'accès.

Une "Guard" de désactivation est un service qui implémente l'interface CanDeactivate.

Ce service doit donc implémenter la méthode canDeactivate. Cette méthode est appelée à chaque fois que l'utilisateur souhaite quitter la route (clic sur un lien ou déclenchement automatique) ; elle doit alors retourner une valeur de type boolean ou Promise<boolean> ou Observable<boolean> indiquant si l'accès à la "route" est autorisé ou non.

Contrairement au "Guards" d'activation, cette "Guard" prend en premier paramètre l'instance du composant. C'est pour cette raison que l'interface CanDeactivate est générique.

La "Guard" appelle la méthode isDirty du composant ProfileViewComponent pour décider d'autoriser ou non l'utilisateur à quitter la route.

Malheureusement, la "Guard" est fortement couplée avec le composant ProfileViewComponent.

@Injectable({
    providedIn: 'root'
})
export class IsNotDirtyGuard implements CanDeactivate<ProfileViewComponent> {

    canDeactivate(component: ProfileViewComponent,
                  currentRoute: ActivatedRouteSnapshot,
                  currentState: RouterStateSnapshot,
                  nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        return component.isDirty();
    }

}
export class ProfileViewComponent {

    isDirty() {
        return false;
    }

}

Pensez à associer la "Guard" à une interface plutôt qu'au composant directement.

export interface IsDirty {
    isDirty(): boolean | Observable<boolean>;
}

@Injectable({
    providedIn: 'root'
})
export class IsNotDirtyGuard implements CanDeactivate<IsDirty> {

    canDeactivate(component: IsDirty,
                  currentRoute: ActivatedRouteSnapshot,
                  currentState: RouterStateSnapshot,
                  nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        return component.isDirty();
    }

}
export class ProfileViewComponent implements IsDirty {

    isDirty() {
        return false;
    }

}
https://blog.wishtack.com/api-rest-bonnes-pratiques-et-securite/