2016-03-22 3 views
8

Я создаю систему аутентификации в angular2 с идеей, что если пользователь, который не прошел аутентификацию, пытается перейти к «защищенному» URL-адресу, система перенаправит пользователя на страницу входа в систему, url параметр запроса, называемый «следующий», который поможет системе входа в систему перенаправить пользователя обратно туда, где он хотел быть в первую очередь.Angular2 Redirect After Login

login?next=my-redirect-url

Для защиты своих компонентов, я использую декоратор @CanActivate(isUserAuthenticated) во всех из них. isUserAuthenticated функция что-то выглядит следующим образом:

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

Этот подход не работает, потому что urlPath свойство nextInstr не показывает «полный» URL (в нем отсутствует параметры запроса, например).

Есть ли способ построить полный URL-адрес от экземпляра ComponentInstruction, например nextInstr?

+0

Вы видели дискуссию в https://github.com/angular/angular/issues/4112 Я думаю, что это очень похоже на то, что вы пытаетесь выполнить. Существует также ссылка на Plunker (не было более пристального взгляда). –

+0

@ GünterZöchbauer спасибо за ссылку, но я уже решил проблему, как получить инжектор внутри декоративной функции 'isUserAuthenticated'. Моя проблема заключается в том, как создать URL-адрес для перенаправления пользователя после входа в систему. –

+0

Я не читал все детали, но у меня создалось впечатление, что они обсуждали параметры запроса. Извините за шум. –

ответ

5

Да есть способ:

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

Допустим, следующий пример структуры в зависимости от routeconfig:

login?next=my-redirect-url 

А затем использовать navigateByUrl, чтобы перейти к следующему адресу

router.navigateByUrl('/' + url); 

Я проверил его с моим примером, и результат вы можете увидеть на изображении:

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

enter image description here

13

Другой способ (без использования параметров запроса, используя @ угловые/маршрутизатор 3.0.0) для достижения того же требование перенаправления к исходному запрошенному ресурсу после аутентификации является использование RouterStateSnapshot.url, который представляет собой строка, содержащая URL-адрес ресурса, запрошенного пользователем. Прежде чем перенаправлять пользователя обратно в вашу регистрационную форму после неудачной попытки аутентификации, внутри крюка CanActivate, получите запрошенный url от RouterStateSnapshot.url и сохраните его в переменной, доступной для вашей функции входа. Когда пользователь регистрируется успешно, просто перенаправляется на сохраненный URL. Вот мой пример:

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

} 

Мои AuthService (ниже), который выполняет вход в систему, будет перенаправлять пользователя на первоначально запрошенный ресурс об успешном входе в систему.

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

Так ваше приложение может запомнить первоначально запрошенный ресурс БЕЗ использования параметров запроса.

Для получения более подробной информации см примера руководство по angular.io, начиная с раздела «Гвардией админ фича»: https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard

Надеется, что это помогает кому-то.