Angular2 登录后重定向

12

我在angular2中创建了一个认证系统,如果未经身份验证的用户试图导航到“保护”网址,则该系统将重定向用户到登录页面,并在url中添加一个名为“next”的查询参数,以帮助登录系统将用户重定向回最初想要进入的位置。

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;
    }
}
这种方法不起作用,因为nextInstrurlPath属性没有显示“完整”的url(例如缺少查询参数)。
是否有一种方法可以从类似于nextInstrComponentInstruction实例构建完整的url?

你看过在https://github.com/angular/angular/issues/4112的讨论吗?我认为这与你尝试完成的相当相似。 还有一个指向Plunker的链接(我自己还没有仔细看)。 - Günter Zöchbauer
@GünterZöchbauer 谢谢你提供的链接,但我已经解决了如何将注入器放置在装饰函数 isUserAuthenticated 中的问题。我的问题是如何生成登录后重定向用户返回的 URL。 - David Barreto
我没有仔细阅读所有细节,但我有印象他们也讨论了查询参数。那么对于噪音我很抱歉。 - Günter Zöchbauer
2个回答

15
另一种实现在认证后重定向到原始请求资源的方法(不使用查询参数,使用@angular/router 3.0.0)是使用RouterStateSnapshot.url。该字符串包含用户请求的资源的URL。在失败的身份验证尝试后将用户重定向回登录表单之前,在CanActivate钩子中,从RouterStateSnapshot.url获取所请求的URL,并将其存储在一个可访问您的登录函数的变量中。当用户成功登录时,只需重定向到存储的URL即可。以下是示例:
//GuardService - 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上的示例指南,从“GUARD THE ADMIN FEATURE”部分开始: https://angular.io/guide/router#guard-the-admin-feature

希望这能对某些人有所帮助。


8

是的,有一种方法:

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

假设以下结构示例取决于路由配置:
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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接