web-dev-qa-db-fra.com

Vérifier si l'utilisateur connecté sur n'importe quelle page a changé Angular 2

Progressant lentement mais sûrement avec Angular2. Et maintenant, j'ai relevé le défi suivant. Je veux vérifier si l'utilisateur est connecté ou non à chaque changement de page (en d'autres termes, en charge de chaque composant). Bien sûr, je peux implémenter l’interface OnInit dans chacun d’eux, mais c’est une odeur de code.

Existe-t-il un moyen efficace d'exécuter tout ce qui est nécessaire sur chaque page de l'application? J'aimerais entendre d'autres suggestions sur les meilleures pratiques pour gérer cette tâche.

J'utilise cette bibliothèque ( https://auth0.com/blog/2015/11/10/introducing-angular2-jwt-a-library-for-angular2-authentication/ ) pour la connexion avec jwt et j'ai déjà avoir une classe de service Nice qui encapsule toutes les fonctionnalités liées à l’authentification. Ainsi, la vérification réelle où l'utilisateur est connecté ou non est déjà faite et testée.

Merci,

7

Si vous utilisez le routage (et cela semble être le cas puisque vous dites: "à chaque changement de page"), vous pouvez tirer parti de plusieurs choses:

  • Créez un routeur-prise personnalisé (une sous-classe de RouterOutlet) qui vérifie l'authentification avec sa méthode activate est appelée. Dans ce cas, vous pouvez avoir quelque chose de global. Quelque chose comme ca:

    @Directive({
      selector: 'auth-outlet'
    })
    export class AuthOutlet extends RouterOutlet {
      (...)
    
      activate(oldInstruction: ComponentInstruction) {
        var url = this.parentRouter.lastNavigationAttempt;
        if (isAuthenticated()) {
          return super.activate(oldInstruction);
        } else {
          (...)
        }
      }
    }
    

    Voir cette question pour plus de détails:

  • Tirez parti du décorateur CanActivate pour vérifier si un composant peut être activé ou non. Dans votre cas, vous pouvez exécuter la vérification d'authentification à ce niveau.

  • Vous pouvez également faire quelque chose au niveau RouterLink pour afficher/masquer les liens de route. Dans ce cas, vous pouvez appliquer des rôles sur ces liens en fonction de la configuration de l'itinéraire et des indications pour l'utilisateur actuel. Voir cette question pour plus de détails:

Cela peut également être géré dans un intercepteur HTTP (une classe qui étend la variable Http). Dans ce cas, lorsqu'une demande est en cours d'exécution, vous pouvez connecter quelques contrôles d'authentification:

@Injectable()
export class CustomHttp extends Http {
  constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) {
    super(backend, defaultOptions);
  }

  request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    console.log('request...');
    if (isAuthenticated()) {
      return super.request(url, options).catch(res => {
        // do something
      });        
    } else {
      // Redirect to login page
      // Or throw an exception: return Observable.throw(new Error(...));
    }
  }

  (...)
}

Voir cette question pour plus de détails:

6
Thierry Templier

Je vous montre une implémentation simple avec Angular2. Vous pouvez tirer parti du hook @CanActivate comme indiqué pour vérifier si l'utilisateur est connecté ou non à la fonction isLoggedIn qui renvoie promise.

NOTE: l'implémentation ci-dessous doit vérifier si l'utilisateur est loggedIn avant d'accéder à un composant ou non. J'espère que par quelques modifications vous pourrez réaliser ce que vous voulez avoir.

Auth.ts

import {Observable} from 'rxjs/Observable';

export class Auth {
  constructor() {
    this.loggedIn = false;
  }

  login() {
    this.loggedIn = true;
  }

  logout() {
    this.loggedIn = false;
  }

  check() {
    return Observable.of(this.loggedIn);
  }
}

isLoggedIn.ts

import {Injector} from 'angular2/core';
import {appInjector} from './appInjector';
import {Auth} from './Auth';
import {Router, ComponentInstruction} from 'angular2/router';

export const isLoggedIn = (next: ComponentInstruction, previous: ComponentInstruction) => {
    let injector: Injector = appInjector(); // get the stored reference to the injector
    let auth: Auth = injector.get(Auth);
    let router: Router = injector.get(Router);

  // return a boolean or a promise that resolves a boolean
    return new Promise((resolve) => {
      auth.check()
          .subscribe((result) => {
                    if (result) {
                        resolve(true);
                    } else {
                        router.navigate(['/Login']);
                        resolve(false);
                    }
                });
  });
};

appInjector.ts

import {Injector} from 'angular2/core';

let appInjectorRef: Injector;
export const appInjector = (injector?: Injector):Injector => {
    if (injector) {
      appInjectorRef = injector;
    }

    return appInjectorRef;
};

somecomponent.ts

import {Component, View,ViewChild} from 'angular2/core';
import {CanActivate} from 'angular2/router';
import {isLoggedIn} from './isLoggedIn';

@Component({
  selector: 'some',
  template: 'some text'
})
@CanActivate((next: ComponentInstruction, previous: ComponentInstruction) => {
  return isLoggedIn(next, previous);  // this will tell whether user is loggedIn or not. 
})
export class Protected {
}

boot.ts

.
.
import { provide, ComponentRef } from 'angular2/core';
import { appInjector } from './app-injector';
.
.
bootstrap(AppComponent, [...]).then((appRef: ComponentRef) => {
  // store a reference to the application injector
  appInjector(appRef.injector);
});

Il existe deux manières de restreindre l'accès Custom Router Outlet et CanActivate Decorator présentés et mis en œuvre dans cet article formidable Authentification in Angular 2

2
micronyks

Je pense que l’extension de RouterOutlet est un moyen courant d’atteindre cet objectif.

Exemple posté il y a quelque temps dans Gitter par CaptainCodeman (pas encore testé)

  import {Directive, Injector, Attribute, ElementRef, DynamicComponentLoader} from 'angular2/core';
  import {Router, RouteData, RouterOutlet, RouteParams, Instruction, ComponentInstruction} from 'angular2/router';

  /*
    Example implementation

    Given a route:
    @RouteConfig([
    { path: '/thing/:id', component: ThingComponent, name: 'Thing', data: { public: false, roles:['thinger'] } }
    ])

    authorize(instruction: ComponentInstruction):boolean {
      // simplest case - route is public
      if (<boolean>instruction.routeData.data['public']) {
        return true;
      }

      // if not public then we at least need an authenticated user
      if (this.isAuthenticated()) {
        var routeRoles = <any[]>instruction.routeData.data['roles'];
        var userRoles = <string[]>this.roles();

        // no roles required for route = user just needs to be authenticated
        var authorized = routeRoles.length === 0 || routeRoles.some(routeRole => userRoles.indexOf(routeRole) >= 0);

        return authorized;
      }

      return false;
    }
  */
  export abstract class IAuthService {
    abstract isAuthenticated():boolean;
    authorize(instruction: ComponentInstruction, params:any):boolean {
      // authorized if route allows public access or user is authenticated
      return this.isAuthenticated() || <boolean>instruction.routeData.data['public']
    }
  }
@Directive({selector: 'secure-outlet'})
  export class SecureRouterOutlet extends RouterOutlet {
    signin:string;
    unauthorized:string;
    injector:Injector;

    private parentRouter: Router;
    private authService: IAuthService;

    constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,
                _parentRouter: Router, @Attribute('name') nameAttr: string,
                authService:IAuthService,
                injector:Injector,
                @Attribute('signin') signinAttr: string,
                @Attribute('unauthorized') unauthorizedAttr: string) {
      super(_elementRef, _loader, _parentRouter, nameAttr);
      this.parentRouter = _parentRouter;
      this.authService = authService;
      this.injector = injector;
      this.signin = signinAttr;
      this.unauthorized = unauthorizedAttr;
    }

    activate(nextInstruction: ComponentInstruction): Promise<any> {
      var params = this.getAllRouteParams(this.injector);
      var isAuthorized = this.authService.authorize(nextInstruction, params);

      if (isAuthorized) {
        return super.activate(nextInstruction);
      }

      if (this.authService.isAuthenticated()) {
        var ins = this.parentRouter.generate([this.unauthorized]);
        return super.activate(ins.component);
      } else {
        var ins = this.parentRouter.generate([this.signin,{url:location.pathname}]);
        return super.activate(ins.component);
      }
    }

    reuse(nextInstruction: ComponentInstruction): Promise<any> {
      return super.reuse(nextInstruction);
    }

    getAllRouteParams(injector) {
      let params = null;
      while(injector) {
        const routeParams = injector.getOptional(RouteParams);
        if (routeParams) {
          if (params === null) {
            params = {};
          } else {
            params = Object.create(params);
          }

          Object.assign(params, routeParams.params);
        }
        injector = injector.parent;
      }
      return params;
    }
  }
1