[NGX]Angular路由守卫初探(1)

4,003 阅读2分钟

何时使用

  1. 用户无权导航到目标组件
  2. 用户得先登录认证
  3. 显示目标组件前,需要先获得某些数据
  4. 离开组件前,需要先保存修改,需要询问用户是否放弃修改

使用方法

  1. 路由守卫返回一个值Observable / Promise,以控制路由器的行为:

    • 返回true,导航继续
    • 返回false,导航终止
  2. 一般项目都会有多层路由和模块懒加载,因此在路由的每个层次上,我们都可以设置多个守卫。路由检查顺序:

    • 从最深的子路由从下往上检查CanDeactivate()和CanActivateChild()守卫。
    • 自上而下检查CanActivate()守卫。

    在上面的过程中,如果模块是lazyLoad的,加载之前还会检查CanLoad()守卫。

    检查过程中任何一个守卫返回false,其他未完成的守卫会被取消,整个导航就会被取消。

  3. 几个路由守卫

    守卫 功能
    CanActivate 导航某路由的情况
    CanActivateChild 导航某子路由的情况
    CanDeactivate 从当前路由离开的情况
    Resolve 路由激活前获取路由数据
    CanLoad 异步导航到某特性模块(懒加载)

CanActivate: 要求认证

一般用来管理访问者是否有权限访问该特性模块或组件;

在根模块下面创建一个service文件夹,用来存放公共的service

// /src/app/service/auth-guard.service.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthGuardService implements CanActivate {
    constructor(private router: Router, private http: HttpClient) {}

    canActivate(): Observable<any> {
        console.log('canActivate goes here');
        // 这里返回一个Observable<boolean>
        return this.http.get('/api/isLogin').map(item => {
            return item['success'];
        });
    }
}

然后打开根模块的routing模块, 注入AuthGuardService:

// /src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuardService } from './service/auth-guard.service';

const appRoutes: Routes = [
    { path: 'view', loadChildren: 'app/core/main/main.module#MainModule', canActivate: [AuthGuardService] },
    { path: 'schedule', loadChildren: 'app/core/schedule/schedule.module#ScheduleModule' },
    { path: 'system', loadChildren: 'app/core/system/system.module#SystemModule' },
    { path: '', redirectTo: 'view/order', pathMatch: 'full' },
];

@NgModule({
    imports: [RouterModule.forRoot(appRoutes, {
        enableTracing: true, // <-- debugging purposes only
    })],
    exports: [RouterModule],
    providers: [AuthGuardService]
})
export class AppRoutingModule {}

以上会使整个模块的访问受限,如果要设置特定组件是否可以访问,则需要注入到相应的特性模块的routing模块,方法相同

CanDeactivate: 处理未保存的修改

用异步的方式等待服务器答复之前先停止导航,canDeactivate方法提供了当前组件,当前ActivatedRoute个RouterStateSnapshot实例。 下面这个Guard可以被所有组件复用

// /src/app/service/can-deactivate.service.ts
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { CanDeactivate,
         ActivatedRouteSnapshot,
         RouterStateSnapshot }  from '@angular/router';


export interface CanComponentDeactivate {
    canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

@Injectable()
export class CanDeactivateService implements CanDeactivate<CanComponentDeactivate> {
    canDeactivate (
        component: CanComponentDeactivate,
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ) {
        console.log('Deactivate goes here', component);
        return component.canDeactivate ? component.canDeactivate() : true;
    }
}

当然也可以单独为某个组件创建属于他自己的canDeactivate-guard,创建完guard后,我们需要为组件创建他的canDeactivate()方法,这个方法返回一个Observable或Promise或boolean,最后加给routing模块对应route的canDeactivate数组中即可;