在Angular中保存/恢复路由器状态

时间:2017-06-14 13:58:36

标签: angular angular-routing

当用户到达我的应用程序中的路由时,该路由受到特殊保护,我将其重定向到登录路由,以便执行身份验证。

然而,在成功认证后,我不想将她重新引导回她最初到达的路线。

如何在Angular中保留中间路由状态,然后重定向到它?

通过路由状态我的意思如下:

  • 路线本身,即路径
  • 所有查询字符串参数
  • 哈希字符串

2 个答案:

答案 0 :(得分:1)

稍微使用路由器之后,我终于设法实现了我想要的解决方案。我将在这里与你分享。

所以这是IntermediateNavigationService的实现:

import {Subscription} from 'rxjs/Subscription';
import {NavigationCancel, NavigationEnd, Router} from '@angular/router';
import {Injectable} from '@angular/core';


@Injectable()
export class IntermediateNavigationService {

  private savedUrl: string;
  private routerSubscription: Subscription;


  constructor (private router: Router) {
  }


  startWatch () {
    this.routerSubscription = this.router.events
      .subscribe(event => {
        if (event instanceof NavigationCancel) {
          // Saving URL from canceled route.
          this.saveUrl(event.url);
        } else if (event instanceof NavigationEnd) {
          // If user navigates away from sign-in page, clearing saved URL.
          if (!event.url.match(/^\/sign-in/)) {
            if (this.hasSavedUrl()) {
              this.clearSavedUrl();
            }
          }
        }
      })
    ;
  }

  stopWatch () {
    this.routerSubscription.unsubscribe();
  }

  saveUrl (url: string) {
    this.savedUrl = url;
  }

  hasSavedUrl () {
    return !!this.savedUrl;
  }

  getSavedUrl () {
    return this.savedUrl;
  }

  clearSavedUrl () {
    this.savedUrl = null;
  }

  goToSavedUrl (): Promise<boolean> {
    return this.router.navigateByUrl(this.savedUrl).then(result => {
      if (result) {
        this.clearSavedUrl();
      }
      return result;
    });
  }

}

这项服务背后的想法非常简单。当由startWatch()方法激活时(您应该尽早在应用程序生命周期中执行此操作,例如在AppComponent构造函数中),它会开始监视路由器事件,专门过滤NavigationCancelNavigationEnd个事件

  • NavigationCancel发生时,意味着我们的身份验证路由防护无法导航到目标路由。因此,我们将跳过的URL保存在服务私有变量中。

  • NavigationEnd发生时,我们会检查用户是否离开我们的登录路线。在这种情况下,我们不再对保留已保存的URL感兴趣,因此我们正在清除它。否则,当用户被重定向到他不再感兴趣的URL时,可能会导致奇怪的行为。

成功登录后,我们应该发出以下代码:

if (this.intermediateNavigationService.hasSavedUrl()) {
  this.intermediateNavigationService.goToSavedUrl();
} else {
  this.navigationService.redirectAfterSignIn();
}

很简短:我们只是检查是否有保存的网址,然后导航到它,如果没有重定向到默认网址。

如果您不再对某个时刻监控状态感兴趣,只需拨打stopWatch()即可取消路由器事件订阅。可以在成功登录后实际保存资源(如果您不打算将此服务用于与身份验证无关的类似行为)。

如果用户已经过身份验证,则无需致电startWatch()

以下是AppComponent的外观:

import {Component as NgComponent} from '@angular/core';

import {AuthenticationStateService} from './authentication/authentication-state.service';
import {IntermediateNavigationService} from './services/intermediate-navigation.service';


@NgComponent({})
export class MyAppComponent {

  constructor (
    private authenticationStateService: AuthenticationStateService,
    private intermediateNavigationService: IntermediateNavigationService
  ) {

    // Enabling intermediate URL handling.
    if (!this.authenticationStateService.isAuthenticated()) {
      this.intermediateNavigationService.startWatch();
    }

    // Listening for authentication event.
    this.authenticationStateService.onAuthenticated().subscribe(() => {
      this.intermediateNavigationService.stopWatch()
    });

  }

}

我希望它会帮助别人。

答案 1 :(得分:0)

一种方法是使用服务。

以下是一个示例服务:

import { Injectable } from '@angular/core';

import { IUser } from './user';
import { MessageService } from '../messages/message.service';

@Injectable()
export class AuthService {
    currentUser: IUser;
    redirectUrl: string;

    constructor(private messageService: MessageService) { }

    isLoggedIn(): boolean {
        return !!this.currentUser;
    }

    login(userName: string, password: string): void {
        if (!userName || !password) {
            this.messageService.addMessage('Please enter your userName and password');
            return;
        }
        if (userName === 'admin') {
            this.currentUser = {
                id: 1,
                userName: userName,
                isAdmin: true
            };
            this.messageService.addMessage('Admin login');
            return;
        }
        this.currentUser = {
            id: 2,
            userName: userName,
            isAdmin: false
        };
        this.messageService.addMessage(`User: ${this.currentUser.userName} logged in`);
    }

    logout(): void {
        this.currentUser = null;
    }
}

完整代码在此处:https://github.com/DeborahK/Angular-Routing

但是如果你找不到它......这里是登录组件代码:

import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Router } from '@angular/router';

import { AuthService } from './auth.service';

@Component({
    templateUrl: './app/user/login.component.html'
})
export class LoginComponent {
    errorMessage: string;
    pageTitle = 'Log In';

    constructor(private authService: AuthService,
                private router: Router) { }

    login(loginForm: NgForm) {
        if (loginForm && loginForm.valid) {
            let userName = loginForm.form.value.userName;
            let password = loginForm.form.value.password;
            this.authService.login(userName, password);

            if (this.authService.redirectUrl) {
                this.router.navigateByUrl(this.authService.redirectUrl);
            } else {
                this.router.navigate(['/products']);
            }
        } else {
            this.errorMessage = 'Please enter a user name and password.';
        };
    }
}

要完成身份验证服务:

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, Router, Route,
         CanActivate, CanActivateChild, CanLoad } from '@angular/router';

import { AuthService } from './auth.service';

@Injectable()
export  class AuthGuard implements CanActivate, CanActivateChild, CanLoad {

constructor(private authService: AuthService,
            private router: Router) { }

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    console.log('In canActivate: ' + state.url);
    return this.checkLoggedIn(state.url);
}

canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    console.log('In canActivateChild: ' + state.url);
    return this.checkLoggedIn(state.url);
}

canLoad(route: Route): boolean {
    console.log('In canLoad: ' + route.path);
    return this.checkLoggedIn(route.path);
}

checkLoggedIn(url: string): boolean {
    if (this.authService.isLoggedIn()) {
        return true;
    }

    // Retain the attempted URL for redirection
    this.authService.redirectUrl = url;
    this.router.navigate(['/login']);
    return false;
}

}

相关问题