# Route Guards

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)*.

{% hint style="danger" %}
**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** : <https://blog.wishtack.com/api-rest-bonnes-pratiques-et-securite/>.

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.
{% endhint %}

## Configuration

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

```typescript
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.

{% tabs %}
{% tab title="is-signed-in.guard.ts" %}

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

    constructor(private _session: Session) {
    }

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

}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
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 :

```typescript
    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;

    }
```

{% endhint %}

## `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.

{% hint style="warning" %}
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`.

```typescript
@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();
    }

}
```

```typescript
export class ProfileViewComponent {

    isDirty() {
        return false;
    }

}
```

{% endhint %}

{% hint style="success" %}
Pensez à associer la "Guard" à une interface plutôt qu'au composant directement.

```typescript
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();
    }

}
```

```typescript
export class ProfileViewComponent implements IsDirty {

    isDirty() {
        return false;
    }

}
```

{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://guide-angular.wishtack.io/angular/routing/route-guards.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
