2016-03-22 20 views
8

Tworzę system uwierzytelniania w kanale2 z myślą, że jeśli użytkownik, który nie jest uwierzytelniony, spróbuje przejść do "chronionego" adresu URL, system przekieruje użytkownika do strony logowania wprowadzając url zapytanie o nazwę "next", które pomoże systemowi logowania przekierować użytkownika z powrotem tam, gdzie chciał być na pierwszym miejscu.Przekierowanie Angular2 po zalogowaniu

login?next=my-redirect-url

Aby chronić swoje komponenty, używam dekorator @CanActivate(isUserAuthenticated) we wszystkich z nich. Funkcja isUserAuthenticated jest czymś, co następuje:

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; 
    } 
} 

Takie podejście nie działa, ponieważ własność nextInstrurlPath nie pokazuje „pełną” url (brakuje params zapytań na przykład).

Czy istnieje sposób na zbudowanie pełnego adresu URL z instancji ComponentInstruction, np. nextInstr?

+0

Czy widziałeś dyskusję na https://github.com/angular/angular/issues/4112 Myślę, że jest dość podobny do tego, co próbujesz osiągnąć. Jest też link do Plunkera (samemu się jeszcze nie przyjrzałem). –

+0

@ GünterZöchbauer dziękuję za link, ale już rozwiązałem problem, jak uzyskać wtryskiwacz wewnątrz funkcji dekoracyjnej 'isUserAuthenticated'. Mój problem polega na tym, jak wygenerować adres URL, aby przekierować użytkownika z powrotem po zalogowaniu. –

+0

Nie czytałem wszystkich szczegółów, ale miałem wrażenie, że omawiali także parametry zapytań. Przepraszamy za hałas. –

Odpowiedz

5

Tak istnieje sposób:

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

Powiedzmy po Przykładowa struktura zależności routeconfig:

login?next=my-redirect-url 

A potem użyć navigateByUrl aby przejść do następującego adresu URL

router.navigateByUrl('/' + url); 

Przetestowałem to z moim przykładem i wynikiem, który możesz zobaczyć na obrazku:

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

enter image description here

13

Inny sposób (bez użycia parametrów zapytania używając @ kątowy/router 3.0.0), aby osiągnąć ten sam wymóg przekierowanie do pierwotnego żądany zasób po autoryzacji jest korzystanie RouterStateSnapshot.url, który jest ciąg zawierający adres URL zasobu, którego zażądał użytkownik. Przed przekierowaniem użytkownika z powrotem do formularza logowania po nieudanej próbie uwierzytelnienia, w haku CanActivate, uzyskaj żądany adres URL z RouterStateSnapshot.url i przechowuj go w zmiennej dostępnej dla funkcji logowania. Gdy użytkownik zaloguje się pomyślnie, po prostu przekieruj do zapisanego adresu URL. Oto mój przykład:

//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; 
    } 

} 

My AuthService (poniżej), który wykonuje logowanie, przekieruje użytkownika do pierwotnie żądanego zasobu na udanym logowaniu.

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 
    } 
} 

W ten sposób aplikacja może zapamiętać pierwotnie żądany zasób BEZ używania parametrów zapytania.

Szczegółowe informacje można znaleźć w instrukcji przykład w angular.io zaczynając od sekcji „straż funkcja ADMIN”: https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard

Hope this helps kogoś.

Powiązane problemy