我正在将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吗?非常感谢
我试图尽可能清楚地描述我的问题。如果您缺少某些信息,请在评论中让我知道,我将更新我的问题。我搜索了许多小时以解决此问题,但找不到任何东西,或者我只是使用了错误的搜索关键字。我希望这也会对其他人有所帮助。
答案 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);
时,几乎可以肯定有两件事是错的:
Observables
,并且subscribe
或subsrciption
这是您在代码中遇到的两个确切错误。
发生错误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>