Angular Route Guard 基于集合查询结果

Angular Route Guard based on collection query result

我在 Firestore 中有一个 'Teams' 集合。团队文档将包含一个 team_users 映射字段,其中 userID: true 如果他们是该团队的一部分。

我在服务中有一个查询,returns 并显示所有团队文档,其中登录的用户 ID 与 team_users 字段中的 ID 匹配。

getTeamsList(user_id: string) {
  this.teamsCollection = this.afs.collection<any>(`teams`, ref => ref.where(`team_users.${user_id}`, "==", true))
  this.teams = this.teamsCollection.snapshotChanges().pipe(
  map(actions => actions.map(a => {
    const data = a.payload.doc.data();
    const id = a.payload.doc.id;
    return { id, ...data };
  }))
 ).pipe(shareReplay());
}

我需要实现的是执行以下操作的路由守卫:

  1. 防止用户访问他们不属于/不属于的团队。例如,如果用户在 Team A 时有一个文档书签,但后来离开了,他们不应该能够访问此路由,而是应该被重定向回 url /teams
  2. 如果用户不属于任何团队(集合查询不产生任何结果),则无法访问 /teams 列表中的部分路由 url

注意:一个用户可以是多个团队的一员。如果用户是 A、B 和 C 团队的一部分,并且拥有 A 团队页面的书签,但已经离开,则路由守卫应该阻止他们访问属于 A 团队的任何页面,但仍然允许访问团队 B 和 C 页面。

这是否意味着:

  1. 我的应用程序中的每个 URL 都需要这个守卫?
  2. 我的应用程序中的每个 URL 都需要包含团队 ID?

如有任何帮助,我们将不胜感激。

你可以这样做: 1.做一个Auth guard,说出来"AG"。 2. 在此 "AG" 中,对您的后端进行 REST 调用。发送书签 ID、用户 ID、当前团队 ID。 "AG" 将在任何应用的路线更改时触发。 3. 此 REST 调用将比较当前团队 ID 和使用该书签保存的团队 ID(假设:书签 table 将团队 ID 列作为外键)。 4、所以当服务returnTRUE/FALSE时,那么"AG"就会知道是否授权了。 5. 如果为 FALSE,则将用户路由到 url.

示例代码示例:

@Injectable()
export class AuthGuardService implements CanActivate 
{ 
   constructor(public auth: AuthService, public router: Router) {}  

   canActivate(): boolean 
   {
    if (!this.auth.isAuthenticated()) {
      this.router.navigate(['team']);
      return false;
    }
    return true;
    }
}

添加路线示例:

export const ROUTES: Routes = [
  { path: '', component: Home},
  { 
    path: 'team/{id}',
    component: TeamComponent,
    canActivate: [AuthGuard] 
  },
  { path: '**', redirectTo: '' }
];

一位用户正在 /teams 页面上显示团队(这条路线不需要守卫)。当用户点击其中一个团队时,导航到 /teams/teamID(现在这条路线需要一个守卫来防止不属于 teamID 的用户访问它。要设置守卫,请执行以下操作:

  1. 编写一个函数来检查 firestore 上的用户是否是团队成员。

isTeamMember(userId: string, teamId: string): Observable < Boolean > {
  return this.firestore.doc < any > (`teams/${teamId}`).snapshotChanges().pipe(
    map(value => value.payload.data().team_users[userId] === true));
}

  1. 调用您的 Guard 中的函数(CanActivate 是这样实现的)。请记住注入包含您当前用户的 service/store 并从 Url 检索 teamId。 2 用于调用 firestore
  2. 上的函数

canActivate(
  next: ActivatedRouteSnapshot,
  state: RouterStateSnapshot): Observable < boolean > | Promise < boolean > | boolean {
  return this.firestoreService.isTeamMember(userIdFromWhereYouStoreYourCurrentUser, teamIdFromTheCurrentUrl).pipe(map(isTeamMember => {
      if (isTeamMember) {
        return true;
      } else {
        //Add your not team member logic here, eg Stay in the current route, may be show an error message
        return false;
      }
    }),
    take(1));
}