用户使用参数访问特定路线

时间:2018-07-07 12:20:23

标签: angular firebase rxjs angularfire2 angular-guards

我正在将Angular与Firebase一起使用。在我的应用程序中,用户可以创建“项目”,并邀请其他用户加入该“项目”,换句话说,一个项目可以有多个用户。我在Firestore中有user个集合和project个集合。

用户集合

users/userID/ -> { name: string }
users集合中的

是具有ID值和数据(名称)的文档

项目收藏

project/projectID/ -> 
{
  projectName: String,
  users: [
    { 
     userID: (here id of user),
     role: String
    }
  ]
project集合中的

是具有ID值和数据的文档。数据是projectName和用户数组。在这一系列用户中,我具有可以访问该项目的用户ID。

场景

用户登录我的应用程序,现在他位于路由/hello的简单介绍页中。现在,用户可以看到他的项目,当他单击某个项目时,他将被路由到此路径/project/:id,在这里他可以使用其他功能,例如/project/:id/overview。它类似于Firebase控制台https://console.firebase.google.com/u/0/project/myprojectid/authentication/users :)我希望我只是澄清我要实现的目标。如果您仍然感到困惑,请在评论中告诉我。

出了什么问题?

在我的项目中,这很好,但是问题是当有人将另一个项目的 id 复制到网址并点击进入时。我想防止用户访问其他用户的项目,因此,如果我在url中输入此路径/project/notMyProject/overview,则应该将我重定向。嗯,那很简单,只需创建我认为的路由器防护即可。所以我开始...

app-routing.module.ts

const routes: Routes = [
  { path: 'project/:pid', component: ProjectComponent, 
   children: [
    { path: '', component: OverviewComponent}, 
    { path: 'users', component: ProjectUsersComponent, }, 
   ],
   canActivate: [ProjectGuard, AuthGuard]
  },
  { path: '', component: PageComponent }
];

project.guard.ts

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../core/auth.service';
import { map } from 'rxjs/operators';
import {
 AngularFirestore,
 AngularFirestoreDocument
} from 'angularfire2/firestore';

@Injectable({
 providedIn: 'root'
})
export class ProjectGuard implements CanActivate {

private itemDoc: AngularFirestoreDocument<any>;
item: Observable<any>;

constructor(
 private auth: AuthService,
 private afs: AngularFirestore,
) {}

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

  this.itemDoc = this.afs.doc<any>.(`project/${next.paramMap.get('pid')}`);

  this.item = this.itemDoc.valueChanges();

  this.item.subscribe(response => {
    console.log(response)
    response.users.forEach( (element) => {
      if(element.userID == this.auth.user.subscribe( data => { return data.uid })) {
        return true;
      }
    })
  })
 }
}

我在这里。我对rxjs和所有这些可观察的东西很陌生。该代码是异步的,我不知道如何使它工作,我收到错误,必须返回Observable或boolean ...

问题

我对这个特定问题的一般做法正确吗?我应该考虑一些更好的选择吗?其他页面如何解决此问题,例如firebase(尝试使用此Firebase)。如果我的解决方案很好,那么您可以为我提供project.guard吗?非常感谢

我试图尽可能清楚地描述我的问题。如果您缺少某些信息,请在评论中让我知道,我将更新我的问题。我搜索了许多小时以解决此问题,但找不到任何东西,或者我只是使用了错误的搜索关键字。我希望这也会对其他人有所帮助。

1 个答案:

答案 0 :(得分:1)

当您看到const ListItem = ({ item }) => <li>{item.text}</li>; const List = ({ listItems }) => ( <div style={{ backgroundColor: 'lightgreen' }} className="border"> I'm List and I get a list of ids from the store. I pass each id to a ListItem. <ul>{listItems.map(item => <ListItem key={item.id} item={item} />)}</ul> </div> ); const ConnectedList = connect(state => ({ listItems: state.listItems, }))(List); 时,几乎可以肯定有两件事是错的:

  1. 执行嵌套的Observables,并且
  2. 将结果分配给subscribesubsrciption

这是您在代码中遇到的两个确切错误。

发生错误1的原因是,在大多数情况下,var result == someObservables.subscribe()是异步的,这也是您的情况,并且您的代码不能确保将返回结果的顺序。您的代码是同步运行的,因此不能故意等待异步任务的执行。这就是为什么Observables存在(地图,过滤器,concatMap等)的原因,这样您就可以处理operators(本身),而不是在Observables最终发出订阅时在订阅之内值。

Mistake 2并不少见,因为Observables的新手总是会认为Observables的结果来自Observables的功能,而事实并非如此。它们出现在订阅回调函数的参数中:

Observables

在理解了两个错误之后,很容易解决代码中的问题。在这里,您需要var thisIsSubscriptionNotResult = myObservable.subscribe(results=>{ var thisisTheRealResult = results; } 的帮助才能将两个不同的combineLatest组合在一起。

observables

上面的代码所做的是将两个可观察变量canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean { this.itemDoc = this.afs.doc<any>(`project/${next.paramMap.get('pid')}`); return Observable .combineLatest(this.itemDoc.valueChanges, this.auth.user) .map(([response, authUser]) => { return response.users.some(x => x.userID === authUser.uid); }); } this.itemDoc.valueChanges组合在一起。但是角度路由器防护器需要一个this.auth.user,因此您需要对其进行映射以将其转换为布尔值。

如果您使用的是rxjs 6,则语法略有不同:

Observable<boolean>