代码之家  ›  专栏  ›  技术社区  ›  Gjert

为Angular 6中的有效防护引发NavigationCancel事件

  •  6
  • Gjert  · 技术社区  · 6 年前

    在导航到提供的状态的过程中,角度路由器出现问题。

    我试过用一个定制的警卫 canLoad() canActivate() 函数将布尔值返回为 true 一点运气都没有。

    棱角分明的 docs

    导航取消:

    控制台输出

    console output

    我创建了一个小项目 here . 这个项目需要访问一个提供者,我正在使用angular-oauth2-oidc存储库中提供的OpenID连接提供者。密码/用户名为max/geheim。

    如何再现错误

    1. 去localhost:4200/oversikt/index
    2. 阅读控制台

    更新 我怀疑这和导航到 children: [] 路线。

    1 回复  |  直到 6 年前
        1
  •  16
  •   Antoniossss    6 年前

    我在你的代码中做了一点调试,我发现这并不是因为链接、auth-guard、导航声明或模块配置 路由器在AG6中呈片状 您正在使用的OAuth库 .

    但让我解释一下。我发现以下情况正在发生:

    1. 您登录并被重定向回页面
    2. 返回应用程序时,请使用类似于/#AUT令牌的链接
    3. 计划首次导航(id 1)
    4. 导航会导致重定向到子页面/过sikt
    5. 导航2弹出(重定向)
    6. 路由器以异步方式执行所有操作-它们是序列化的,但仍然硬使用RxJS-因此实际处理被延迟-它已将当前导航id作为参数传递(这很重要)
    7. 一些侦听器和其他订阅以及您正在使用的OAUTH库中的内容被激发
    8. 它(lib)检测到您的url中有令牌并将其删除
    9. 这将触发另一个重定向-路由id立即增加到3
    10. 因为它有变化-id 2是在计划时间传递的,当前导航是3,单 false
    11. boolean

    我将添加一些代码引用。但总的来说,情况就是这样。您的oauth库在导航期间修改url,这导致它被取消。卫兵们不喜欢直接跟这件事扯上关系。

    所以一般来说-它不是因为“访问被拒绝”而取消的,就像在守卫的情况下,但是它被取消了,因为必须执行新的导航,所以它被取消短路了。

    以下是(并非所有)相关代码:

    OAuth库修改

       if (!this.oidc) {
                this.eventsSubject.next(new OAuthSuccessEvent('token_received'));
                if (this.clearHashAfterLogin && !options.preventClearHashAfterLogin) {
                    location.hash = '';
                }
                return Promise.resolve();
            }
    

     Router.prototype.setUpLocationChangeListener = function () {
            var _this = this;
            // Don't need to use Zone.wrap any more, because zone.js
            // already patch onPopState, so location change callback will
            // run into ngZone
            if (!this.locationSubscription) {
                this.locationSubscription = this.location.subscribe(function (change) {
                    var rawUrlTree = _this.parseUrl(change['url']);
                    var source = change['type'] === 'popstate' ? 'popstate' : 'hashchange';
                    if(this.rou)
                    var state = change.state && change.state.navigationId ?
                        { navigationId: change.state.navigationId } :
                        null;
                    setTimeout(function () { console.error("FROM LOCATION SUB");_this.scheduleNavigation(rawUrlTree, source, state, { replaceUrl: true }); }, 0);
                });
            }
        };
    

    导航id修改-立即发生:

       var id = ++this.navigationId;
        console.error("ANOTHER SCHEDULED LOL LOL LOL!!!");
        this.navigations.next({ id: id, source: source, state: state, rawUrl: rawUrl, extras: extras, resolve: resolve, reject: reject, promise: promise });
        // Make sure that the error is propagated even though `processNavigations` catch
        // handler does not rethrow
        return promise.catch(function (e) { return Promise.reject(e); });
    

     Router.prototype.runNavigate = function (url, rawUrl, skipLocationChange, replaceUrl, id, precreatedState) {
    

    var preactivationCheckGuards$ = preactivationSetup$.pipe(mergeMap(function (p) {
                if (typeof p === 'boolean' || _this.navigationId !== id) //NAVIGATION ID CHANGES HERE!
                {
                  console.warn("PREACTIVATE GUARD CHECK ");
                  console.log(p);
                  // debugger;
                  return of(false);
                }
    

     var preactivationResolveData$ = preactivationCheckGuards$.pipe(mergeMap(function (p) {
                    if (typeof p === 'boolean' || _this.navigationId !== id)
                        return of(false);
    

    注意,这就是我之前写的,如果这里有booean,false会向前推。既然我们有

    最后在链条的末端

        if (typeof p === 'boolean' || !p.shouldActivate || id !== _this.navigationId || !p.state) {
          // debugger;
            navigationIsSuccessful = false;
            return;
        }
    

    结果标志设置为false,这将导致

     .then(function () {
            if (navigationIsSuccessful) {
                _this.navigated = true;
                _this.lastSuccessfulId = id;
                _this.events
                    .next(new NavigationEnd(id, _this.serializeUrl(url), _this.serializeUrl(_this.currentUrlTree)));
                resolvePromise(true);
            }
            else {
                _this.resetUrlToCurrentUrlTree();
                _this.events
                    .next(new NavigationCancel(id, _this.serializeUrl(url), ''));
                resolvePromise(false);
            }
    

    NavigationCancel 没有任何您熟悉的消息(最后一个参数是message-emtpy字符串:)。

    我花了太多的时间,因为我不知道那些该死的管子。。。到处都是管道。

    NavigationCancel:取消导航时触发的事件。这个 是由于导航期间路线卫兵返回false。

    好吧,他们忘了提到,路由器内部可以取消导航,是不是有导航队列在增加:)

    干杯!