2016-03-22 41 views
8

Sto creando un sistema di autenticazione in angular2 con l'idea che se un utente che non è autenticato prova a navigare verso un URL "protetto", il sistema reindirizzerà l'utente alla pagina di accesso che inserisce il url una query param chiamata "next" che aiuterà il sistema di login a reindirizzare l'utente a dove voleva essere in primo luogo.Angolare2 Reindirizza dopo l'accesso

login?next=my-redirect-url

per proteggere i miei componenti, sto usando il decoratore @CanActivate(isUserAuthenticated) in tutti loro. La funzione isUserAuthenticated è qualcosa come segue:

function isUserAuthenticated(
    prevInstr: ComponentInstruction, 
    nextInstr: ComponentInstruction 
): boolean { 
    const authService = injector.get(AuthService); 
    const router = injector.get(Router); 
    if(authService.isLoggedIn()) { 
     return true; 
    } else { 
     router.navigate(["/Login", {next: nextInstr.urlPath}]); 
     return false; 
    } 
} 

Questo approccio non funziona perché la proprietà del nextInstrurlPath non mostra l'url "completo" (manca parametri di query per esempio).

Esiste un modo per creare l'URL completo da un'istanza ComponentInstruction come nextInstr?

+0

Avete visto la discussione in https://github.com/angular/angular/issues/4112 Penso che sia abbastanza simile a ciò che si tenta di realizzare. C'è anche un link a un Plunker (non ho più avuto uno sguardo da vicino). –

+0

@ GünterZöchbauer grazie per il link, ma ho già risolto il problema di come ottenere l'iniettore all'interno della funzione di decorazione 'isUserAuthenticated'. Il mio problema è come generare l'url per reindirizzare l'utente dopo il login. –

+0

Non ho letto tutti i dettagli, ma ho avuto l'impressione di aver discusso anche dei parametri di query. Scusa per il rumore allora. –

risposta

5

Sì, c'è un modo:

let url = router.generate(['./Login', {next: nextInstr.urlPath}]).toRootUrl(); 

Diciamo esempio che segue la struttura a seconda routeconfig:

login?next=my-redirect-url 

e quindi si utilizza navigateByUrl per passare alla seguente URL

router.navigateByUrl('/' + url); 

L'ho provato con il mio esempio e il risultato è visibile sull'immagine:

let instruction = router.generate(['./Country', {country: 'de', a: 1, b: 2}]); 
console.log(instruction, instruction.toRootUrl()); 

enter image description here

13

altro modo (SENZA utilizzando parametri di query utilizzando @ angolare/router 3.0.0) per ottenere lo stesso requisito di reindirizzare alla risorsa richiesta originale dopo autenticazione consiste nell'utilizzare RouterStateSnapshot.url, che è un stringa che contiene l'url della risorsa richiesta dall'utente. Prima di reindirizzare l'utente al modulo di accesso dopo un tentativo di autenticazione fallito, all'interno dell'aggancio CanActivate, ottenere l'URL richiesto da RouterStateSnapshot.url e memorizzarlo in una variabile accessibile alla funzione di accesso. Quando l'utente si collega correttamente, semplicemente reindirizza all'URL memorizzato. Ecco il mio esempio:

//GaurdService - implements CanActivate hook for the protected route 

import { Injectable } from '@angular/core'; 
import { CanActivate, Router, RouterStateSnapshot } from '@angular/router'; 
import { AuthService } from './auth.service'; 

@Injectable() 
export class GuardService implements CanActivate { 
    constructor(private router: Router, private authService: AuthService) {} 

    canActivate(state: RouterStateSnapshot): boolean { 
     let url: string = state.url; 
     return this.checkLogin(url); 
    } 

    checkLogin(url: string): boolean { 
     if (this.authService.loggedIn()) { return true; } 
     this.authService.redirectUrl = url; // set url in authService here 
     this.router.navigate([ '/login' ]); // then ask user to login 
     return false; 
    } 

} 

mio AuthService (sotto), che esegue il login, sarà reindirizzare utente alla risorsa originariamente richiesto al login di successo.

import { Injectable, Inject } from '@angular/core'; 
import { tokenNotExpired } from 'angular2-jwt'; 
import { Router } from '@angular/router'; 
import { Headers, Http, Response, RequestOptions } from '@angular/http'; 
import { Observable } from 'rxjs'; 
import './../rxjs-operators'; 

const API_URL: string = ''; 

@Injectable() 
export class AuthService { 
    public redirectUrl: string = ''; //Here is where the requested url is stored 

constructor(@Inject('API_URL') private apiURL: string, private router: Router, private http: Http) {} 

    public loggedIn(): boolean { 
     return tokenNotExpired('token'); 
    } 

    public authenticate(username: string, password: string) { 
     let body: string = JSON.stringify({ un: username, pw: password}); 
     let headers: Headers = new Headers({ 'Content-Type': 'application/json' }); 
     let options: RequestOptions = new RequestOptions({ headers: headers }); 
     return this.http.post(this.apiURL + '/authenticate', body, options) 
      .map(res => res.json()) 
      .subscribe(res => { 
       localStorage.setItem('token',res.token); 
       this.redirect(); // Redirect to the stored url after user is logged in 
      }); 

     .catch(this.handleError); 
    } 

    private redirect(): void { 
     this.router.navigate([ this.redirectUrl ]); //use the stored url here 
    } 
} 

Ecco come la tua applicazione può ricordare la risorsa originariamente richiesta SENZA usare parametri di query.

Per maggiori dettagli consultare la guida esempio a angular.io a partire dalla sezione "custodire i CARATTERISTICA ADMIN": https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard

Spero che questo aiuti qualcuno.

Problemi correlati