4 votes

Conseils pour Angular 7 et l'authentification CAS ?

J'essaie en fait de comprendre exactement comment tout cela doit fonctionner, en fait, la logique de l'authentification est la suivante.

1) L'utilisateur se rend sur l'application angulaire, clique sur "login" et est redirigé vers "can log in" avec un modèle d'URL comme celui-ci avec mon application angulaire comme paramètre : cas-example.com/login?service=my-angular-app

2) Si l'utilisateur se connecte, rediriger vers l'application angulaire avec un ticket de service dans l'URL, comme ceci : my-angular-app.com/?ticket=ST-1232431

3) Ensuite, je dois envoyer le ticket à mon backend et si le ticket est valide, le backend m'envoie un jwt où je peux me connecter à l'utilisateur.

Cette approche est-elle bonne ? Comment dois-je implémenter le listener à partir du ticket, dois-je vérifier si la redirection vient de cas et vérifier l'URL, ou toujours vérifier l'URL ?

Voici le diagramme du flux de cas : enter image description here

0voto

Francisco Points 1271

C'est un peu difficile d'être concret, mais je vais essayer de vous donner quelques conseils sur la façon de gérer l'authentification dans angular.

Certains outils livrés avec Angular sur lesquels je me concentre sur ce sujet sont : APP_INITIALIZER ( un article sur ce sujet - car les documents sont rares), HttpInterceptor , LoadingComponent ou simplement le composant d'application typique.

Certaines dépendances qui m'aident également dans ce processus sont les suivantes ngx-store et magasin ngxs . Malgré des noms similaires, ce sont des outils différents.

Je ne vais pas vous donner une réponse complète à votre problème, mais quelques conseils :

Dans un service d'authentification, vous pouvez, par exemple, enregistrer un callback pour écouter la modification d'un certain cookie (grâce à ngx -store). Quelque chose comme ceci :

constructor(public cookiesStorageService: CookiesStorageService,
          @Inject(JWT_COOKIE_NAME) private _JWT_COOKIE_NAME: string) {
this.cookiesStorageService
  .observe(this._JWT_COOKIE_NAME)
  .subscribe((cookie: NgxStorageEvent) => this.checkIfNewToken(cookie.newValue));

}

Remarquez que ci-dessus, on injecte le nom du cookie pour le jeton JWT. Je trouve que c'est plus clair et que cela colle aux principes d'Angular :

export const JWT_COOKIE_NAME = new InjectionToken<string>('ACTUAL_JWT_COOKIE_NAME');

Dans le cas ci-dessus, si vous transmettez un jeton JWT via des cookies (pas d'en-tête d'authentification). Si vous passez un en-tête portant le jeton, vous pourriez faire quelque chose comme intercepter les requêtes HTTP. Quelque chose comme :

@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {

    constructor(private tokenExtractor: HttpXsrfTokenExtractor,
          private authService: AuthenticationService,
          @Inject(API_ENDPOINT) private _API_ENDPOINT: string) {
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    if (req.url.match(this._API_ENDPOINT)) {
        // this.authService.intercept$.next(req);

        const XSRFTokenHeaderName = 'X-XSRF-TOKEN';
        const XSRFToken = this.tokenExtractor.getToken() as string;
        if (XSRFToken !== null && !req.headers.has(XSRFTokenHeaderName)) {
          req = req.clone({headers: req.headers.set(XSRFTokenHeaderName, XSRFToken)});
        }

        req = req.clone();

        return next.handle(req);
      } else {
        return next.handle(req).map(event => {
          if (event instanceof HttpResponse) {
              // do something with response like sending it to an authentication service
          }         
          return event;
      });
      }
    }
  }

Je laisse l'exemple canonique du traitement de X-XSRF-TOKEN.

Un initialisateur d'application pourrait faire quelque chose comme distribuer une action de connexion - ou appeler directement une méthode de service d'authentification (j'aime utiliser ngxs store pour ce genre de choses) :

export function appRun(store: Store) {
  return () =>
    store
      .dispatch(new Login())
      .pipe(finalize(() => true)) // let the app handle errors after bootstrapped
      .toPromise();
    }

Et dans un composant de chargement ou le composant d'application ont quelque chose comme ceci :

constructor(
    private router: Router,
    private actions$: Actions
) {}

ngOnInit() {

    this.actions$
      .pipe(ofActionErrored(Login))
      .subscribe(() => this.router.navigate([Routes.PUBLIC]));

    this.actions$
      .pipe(ofActionSuccessful(Logout))
      .subscribe(() => this.router.navigate([Routes.PUBLIC]));
 }

NGXS est livré avec des gestionnaires utiles de succès d'action ou d'erreur d'action que vous pouvez utiliser pour acheminer quelque part (les routes ci-dessus sont définies dans un Enum).

Je laisse donc de nombreuses étapes en dehors de cette réponse (comme la déclaration des états, l'enregistrement de l'APP_INITIALIZER, de l'Interceptor, ...) mais n'hésitez pas si vous pensez que cela peut aider à commenter pour plus d'informations. Les bibliothèques mentionnées sont très puissantes et peuvent vous aider à résoudre votre problème de différentes manières (ou pourraient finir par n'être qu'une surcharge - un service pour stocker certains états et un intercepteur pourraient suffire). Ce n'est pas très concret, mais je pense que c'est un bon ensemble de conseils pour vous aider à démarrer.

edit : J'ai oublié les gardiens de route. Elles peuvent aussi aider à l'authentification dans angular. Les gardes CanLoad (pour les modules chargés paresseusement) et CanActivate en particulier. Quelque chose comme :

canActivateRead(): Observable<boolean> | boolean {
    const perm = this.store.selectSnapshot(state => state.module.acl);
    if (perm) {
      return this.canRead(perm);
    } else {
      return this.fetchACLAndTestPermission('READ');
    }
}

private fetchACLAndTestPermission(perm: 'READ' | 'CREATE' | 'UPDATE'): Observable<boolean> {
    return this.authService.getPermissionForACL('ACL').pipe(
      tap(permission => this.store.dispatch(new SetMainACL({ permission }))),
      map(perm => this.canRead(perm)),
      tap(isPermitted => (isPermitted ? isPermitted : this.feedback.notAllowed()))
);

}

Et vous pouvez hériter dans un service de garde :

@Injectable({
  providedIn: 'root'
})
export class ParameterBaseGuard extends ParameterGuards implements CanLoad {
  constructor(public authService: AuthenticationService, public feedback: FeedbackService, public store: Store) {
    super(authService, feedback, store);
  }
  canLoad(): Observable<boolean> | Promise<boolean> | boolean {
    return this.fetchACLAndTestPermission('READ');
  }
  canActivate(): Observable<boolean> | Promise<boolean> | boolean {
    return this.canActivateRead();
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X