最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular2: how to "reload" page with router (recheck canActivate)? - Stack Overflow

programmeradmin1浏览0评论

I have routers with canActivate: [ AuthGuard ] and validation inside AuthGuard

How to force check canActivate in same router url ?

For example: Current route is /admin and I have got event like session expired. I have session check in AuthGuard but this check activates only when I execute .navigate(...). How to force run canActivate in same location?

I've tried: this.router.navigate([ this.router.url ]); but angular checks same location and do nothing.

p.s. I can locate to "login page" or other pages when I got session expired event, but I have all redirects inside AuthGuard and I do not want to repeat the same redirects in all other events, I need just like location.reload() but in Angular2 routes.

Main question sounds like: How to force rerun canActivate guards in current location?

I have routers with canActivate: [ AuthGuard ] and validation inside AuthGuard

How to force check canActivate in same router url ?

For example: Current route is /admin and I have got event like session expired. I have session check in AuthGuard but this check activates only when I execute .navigate(...). How to force run canActivate in same location?

I've tried: this.router.navigate([ this.router.url ]); but angular checks same location and do nothing.

p.s. I can locate to "login page" or other pages when I got session expired event, but I have all redirects inside AuthGuard and I do not want to repeat the same redirects in all other events, I need just like location.reload() but in Angular2 routes.

Main question sounds like: How to force rerun canActivate guards in current location?

Share Improve this question asked Aug 14, 2017 at 17:54 mixalbl4mixalbl4 3,9951 gold badge35 silver badges47 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 7

My temporary solution:

auth.service.ts

import { Injectable, Injector } from '@angular/core';
import { ActivatedRoute, Router, RouterStateSnapshot } from '@angular/router';

@Injectable()
export class AuthService {

  constructor(private route: ActivatedRoute,
              private router: Router,
              private injector: Injector) {
    this.forceRunAuthGuard();
  }

  // Dirty hack for angular2 routing recheck
  private forceRunAuthGuard() {
    if (this.route.root.children.length) {
      // gets current route
      const curr_route = this.route.root.children[ '0' ];
      // gets first guard class
      const AuthGuard = curr_route.snapshot.routeConfig.canActivate[ '0' ];
      // injects guard
      const authGuard = this.injector.get(AuthGuard);
      // makes custom RouterStateSnapshot object
      const routerStateSnapshot: RouterStateSnapshot = Object.assign({}, curr_route.snapshot, { url: this.router.url });
      // runs canActivate
      authGuard.canActivate(curr_route.snapshot, routerStateSnapshot);
    }
  }

}

app.routes.ts

  { path: 'faq', canActivate: [ AuthGuard ], ponent: FaqComponent },
  { path: 'about', canActivate: [ AuthGuard ], ponent: AboutUsComponent },
  { path: 'upgrade', canActivate: [ AuthGuard ], ponent: UpgradeComponent },

This code runs AuthGuard again.

Unfortunately @mixalbl4's answer is still relevant today, but I tought I'd give it a more generic approach, the code below will work with any AuthGuard:

import { Injectable, Injector } from "@angular/core";
import { ActivatedRoute, CanActivate, CanActivateChild, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
import { concat, concatMap, from, isObservable, last, Observable, of, skip, takeWhile } from "rxjs";

@Injectable()
export class AuthService{
    protected routeSnapshot: RouterStateSnapshot;

    constructor(
        protected route: ActivatedRoute,
        protected injector: Injector,
        protected router: Router){

        this.routeSnapshot = Object.assign({}, this.route.snapshot, { url: this.router.url });
    }

    public checkActivation(){
        this.checkRouteActivation(this.route).subscribe(a => {
            if(a !== true){
                if(a === false)
                    a = this.router.parseUrl("DEFAULT_ROUTE"); // Route to redirect to on activation fail, if not specified by guard

                this.router.navigateByUrl(a as UrlTree);
            }
        });
    }

    private checkRouteActivation(route: ActivatedRoute):Observable<boolean | UrlTree>{
        let conditions:Observable<boolean | UrlTree>[] = [];

        // Check own activation
        if(route.routeConfig){
            if(route.routeConfig.canActivate?.length ?? 0 > 0)
                conditions.push(...route.routeConfig.canActivate!.map(a => this.validateGuard(a, route, false)));

            if(route.routeConfig.canActivateChild?.length ?? 0 > 0)
                conditions.push(...route.routeConfig.canActivateChild!.map(ac => this.validateGuard(ac, route, true)));
        }

        // Add last true (if does not have any activations or parents)
        if(conditions.length == 0)
            conditions.push(of(true));

        let ownObservable = concat(...conditions).pipe(takeWhile(v => v === true, true), last());

        // Validate parent if present
        if(route.parent)
            return this.checkRouteActivation(route.parent).pipe(concatMap(v => v === true ?
                ownObservable :
                of(v)));
        else
            return ownObservable;
    }

    private validateGuard(guardToken: any, route: ActivatedRoute, child:boolean):Observable<boolean | UrlTree>{
        var guard: (CanActivate & CanActivateChild) = this.injector.get(guardToken);
        
        let result:Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;
        if(!child)
            result = guard.canActivate(route.snapshot, this.routeSnapshot);
        else
            result = guard.canActivateChild(route.snapshot, this.routeSnapshot);

        if(isObservable(result))
            return result;
        else if(typeof (result as any)?.then === 'function') // check if is promise
            return from(result as Promise<boolean | UrlTree>);
        else
            return of(result as boolean | UrlTree);
    }
}
发布评论

评论列表(0)

  1. 暂无评论