简体   繁体   English

用于限制用户访问 angular 中特定路由的防护不起作用

[英]Guard for restricting user access to specific routes in angular not working

I am trying to restrict the user access to specific routes depending on the user role.我试图根据用户角色限制用户对特定路由的访问。 I've created a new role guard to do this but am still able to access the restricted routes.Thanks in advance for your help我已经创建了一个新的角色守卫来执行此操作,但仍然能够访问受限制的路线。提前感谢您的帮助

Here is my guard:这是我的后卫:

export class RoleGuard implements CanActivate {

  role: string;
  constructor(private router: Router) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {


    this.getRole().subscribe(data => {
      this.role = data;
    });
    const userRole = JSON.parse(localStorage.getItem('user_role'));
    if (userRole === 'admin'&& this.role === 'ADMIN') {
      // role not authorised so redirect to home page
      this.router.navigate(['']);
      return false;

    }
    else {
      return true;
    }


  }

  getRole(): Observable<any> {
    return this.router.events.pipe(map(data => {
      if (data instanceof ChildActivationStart) {
        return data.snapshot.data.roles;
      }
    }));
  }


}

When I tried logging the role in the guard, I could see the value coming as undefined after the initial admin value which means canActivate is being called multiple times but the getRole method is called only once.当我尝试在警卫中记录角色时,我可以看到在初始管理值之后的值未定义,这意味着 canActivate 被多次调用,但 getRole 方法只被调用一次。 Here is my routing module:这是我的路由模块:

const routes: Routes = [{
  path: '',
  pathMatch: 'prefix',
  component: AppComponent,
  canActivate: [AuthGuard],

  children: [
    {
      path: 'admin',
      canActivate: [RoleGuard],
      data: {
        title: 'Admin Support',
        roles: 'ADMIN'
      },
      loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
    },
    {
      path: 'user',
      loadChildren: () => import('./user/user.module').then(m => m.UserModule)
    }
  ],
}

You are subscribing to an observable but it already exits the method when you check its value.您正在订阅一个 observable,但是当您检查它的值时它已经退出了该方法。

When you hit this.role === 'ADMIN' this.role is equal to undefined当你点击this.role === 'ADMIN' this.role 等于undefined

You should return an Observable from this method你应该从这个方法返回一个 Observable

canActivate(
     next: ActivatedRouteSnapshot,
     state: RouterStateSnapshot): Observable<boolean> {


   return this.getRole().pipe(map(role => {
   const userRole = JSON.parse(localStorage.getItem('user_role'));
   if (userRole === 'admin' && role === 'ADMIN') {
      // role not authorised so redirect to home page
      this.router.navigate(['']);
      return false;
   }
   else {
      return true;
   }));
}

getRole(): Observable<string> {
  return this.router.events.pipe(map(data => {
     if (data instanceof ChildActivationStart) {
        return data.snapshot.data.roles as string;
     }
   }));
}

On a general note you should look into more how observables work一般而言,您应该更多地研究可观察对象的工作原理

As I said, the problem is you are returning inside the subscription and the returning value is never getting outside of the subscription.正如我所说,问题是您在订阅内返回,而返回值永远不会超出订阅。 The idea behind the Angular Guard is that it should inform the router whether or not the navigation is allowed, so the Guard must return something ideally a boolean or an Observable or a Promise that resolves to boolean. The idea behind the Angular Guard is that it should inform the router whether or not the navigation is allowed, so the Guard must return something ideally a boolean or an Observable or a Promise that resolves to boolean.

With that in mind, have a look at the following approach, it might not work by simply copy-pasting it, but should help you to get on track.考虑到这一点,看看下面的方法,它可能无法通过简单的复制粘贴来工作,但应该可以帮助你走上正轨。

export class RoleGuard implements CanActivate {
  role: string;
  constructor(private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return this.router.events.pipe(
      filter((event: RouterEvent) => event instanceof ChildActivationStart),
      // use the tap for debugging purposes (I'm not sure if ChildActivationStart will contain what your are looking for)
      tap((event) => console.log(event)),
      map((event: any) => event.snapshot.data.roles),
      map((role: string) => this.isUserAuthorized(role)),
      tap((authorized: boolean) => {
        if (!authorized) { this.router.navigate(['']); }
      })
    );
  }

  private isUserAuthorized(role: string): boolean {
    try {
      // JSON.parse might fail, it's a good practice to catch the errors
      const userRole = JSON.parse(localStorage.getItem('user_role'));
      return userRole === 'admin' && role === 'ADMIN';
    } catch (e) {
      return false;
    }
  }

}

Don't give up and publish any further errors.不要放弃并发布任何进一步的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM