按顺序执行多个异步路由保护 [英] Execute Multiple Asynchronous Route Guards in Order

查看:65
本文介绍了按顺序执行多个异步路由保护的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道当canActivate函数返回一个简单的boolean时,角路由防护会按指定的顺序执行,但是,如果防护返回类型Observable<boolean>Promise<boolean>,该怎么办?

I know angular route guards execute in the specified order when the canActivate function returns a simple boolean, however, what if the guards return type Observable<boolean> or Promise<boolean>?

路线示例:

{
    path: 'confirm',
    canActivate: [AuthGuard, SessionExpiredAuthGuard, CheckoutAuthGuard],
    component: CheckoutReviewOrderComponent
},

SessionExpiredAuthGuard和CheckoutAuthGuard都返回类型Observable<boolean>.我不希望在SessionExpiredAuthGuard完成从异步http请求中获取其数据之前执行CheckoutAuthGuard.

SessionExpiredAuthGuard and CheckoutAuthGuard both return type Observable<boolean>. I don't want the CheckoutAuthGuard to be executed before the SessionExpiredAuthGuard is finished retrieving it's data from the asynchronous http request.

有什么方法可以强制这些异步防护措施按顺序执行?

Is there any way to force these asynchronous guards to execute in order?

推荐答案

问题

首先,angular不支持串联调用后卫的功能.因此,如果第一个警卫是异步的并且正在尝试进行ajax调用,那么即使在警卫1中完成ajax请求之前,所有剩余的警卫也会被触发.

Problem

First of all, angular doesn't support the feature to call the guards in tandem. So if first guard is asynchronous and is trying to make ajax calls, all the remaining guards will get fired even before completion of the ajax request in guard 1.

我遇到了类似的问题,这就是我的解决方法-

I faced the similar problem and this is how I solved it -

想法是创建一个主防护,并让该主防护处理其他防护的执行.

The idea is to create a master guard and let the master guard handle the execution of other guards.

在这种情况下,路由配置将包含主防护作为唯一防护.

The routing configuration in this case, will contain master guard as the only guard.

要让主警卫知道要为特定路由触发的警卫,请在Route中添加data属性.

To let master guard know about the guards to be triggered for specific routes, add a data property in Route.

data属性是一个键值对,允许我们将数据附加到路由.

The data property is a key value pair that allows us to attach data with the routes.

然后可以使用防护中的canActivate方法的ActivatedRouteSnapshot参数在防护中访问数据.

The data can then be accessed in the guards using ActivatedRouteSnapshot parameter of canActivate method in the guard.

该解决方案看起来很复杂,但是一旦将其集成到应用程序中,它将确保警卫人员正常工作.

The solution looks complicated but it will assure proper working of guards once it is integrated in the application.

以下示例说明了这种方法-

Following example explains this approach -

1.常量对象可映射所有应用程序防护-

export const GUARDS = {
    GUARD1: "GUARD1",
    GUARD2: "GUARD2",
    GUARD3: "GUARD3",
    GUARD4: "GUARD4",
}

2. Application Guard-

import { Injectable } from "@angular/core";
import { Guard4DependencyService } from "./guard4dependency";

@Injectable()
export class Guard4 implements CanActivate {
    //A  guard with dependency
    constructor(private _Guard4DependencyService:  Guard4DependencyService) {}

    canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        return new Promise((resolve: Function, reject: Function) => {
            //logic of guard 4 here
            if (this._Guard4DependencyService.valid()) {
                resolve(true);
            } else {
                reject(false);
            }
        });
    }
}

3.路由配置-

import { Route } from "@angular/router";
import { View1Component } from "./view1";
import { View2Component } from "./view2";
import { MasterGuard, GUARDS } from "./master-guard";
export const routes: Route[] = [
    {
        path: "view1",
        component: View1Component,
        //attach master guard here
        canActivate: [MasterGuard],
        //this is the data object which will be used by 
        //masteer guard to execute guard1 and guard 2
        data: {
            guards: [
                GUARDS.GUARD1,
                GUARDS.GUARD2
            ]
        }
    },
    {
        path: "view2",
        component: View2Component,
        //attach master guard here
        canActivate: [MasterGuard],
        //this is the data object which will be used by 
        //masteer guard to execute guard1, guard 2, guard 3 & guard 4
        data: {
            guards: [
                GUARDS.GUARD1,
                GUARDS.GUARD2,
                GUARDS.GUARD3,
                GUARDS.GUARD4
            ]
        }
    }
];

4.警卫队-

import { Injectable } from "@angular/core";
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router";

//import all the guards in the application
import { Guard1 } from "./guard1";
import { Guard2 } from "./guard2";
import { Guard3 } from "./guard3";
import { Guard4 } from "./guard4";

import { Guard4DependencyService } from "./guard4dependency";

@Injectable()
export class MasterGuard implements CanActivate {

    //you may need to include dependencies of individual guards if specified in guard constructor
    constructor(private _Guard4DependencyService:  Guard4DependencyService) {}

    private route: ActivatedRouteSnapshot;
    private state: RouterStateSnapshot;

    //This method gets triggered when the route is hit
    public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {

        this.route = route;
        this.state = state;

        if (!route.data) {
            Promise.resolve(true);
            return;
        }

        //this.route.data.guards is an array of strings set in routing configuration

        if (!this.route.data.guards || !this.route.data.guards.length) {
            Promise.resolve(true);
            return;
        }
        return this.executeGuards();
    }

    //Execute the guards sent in the route data 
    private executeGuards(guardIndex: number = 0): Promise<boolean> {
        return this.activateGuard(this.route.data.guards[guardIndex])
            .then(() => {
                if (guardIndex < this.route.data.guards.length - 1) {
                    return this.executeGuards(guardIndex + 1);
                } else {
                    return Promise.resolve(true);
                }
            })
            .catch(() => {
                return Promise.reject(false);
            });
    }

    //Create an instance of the guard and fire canActivate method returning a promise
    private activateGuard(guardKey: string): Promise<boolean> {

        let guard: Guard1 | Guard2 | Guard3 | Guard4;

        switch (guardKey) {
            case GUARDS.GUARD1:
                guard = new Guard1();
                break;
            case GUARDS.GUARD2:
                guard = new Guard2();
                break;
            case GUARDS.GUARD3:
                guard = new Guard3();
                break;
            case GUARDS.GUARD4:
                guard = new Guard4(this._Guard4DependencyService);
                break;
            default:
                break;
        }
        return guard.canActivate(this.route, this.state);
    }
}

这种方法的挑战之一是重构现有的路由模型.但是,由于更改是不间断的,因此可以分部分进行.

One of the challenges in this approach is refactoring of existing routing model. However, it can be done in parts as the changes are non-breaking.

我希望这会有所帮助.

这篇关于按顺序执行多个异步路由保护的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆