Angularfire2:关于身份验证更改和权限被拒绝的嵌套可观察对象
Angularfire2: Nested observables on auth change and permission denied
我的用户可以喜欢英雄列表,所以我在我的 firebase 中有这个结构 rules/datas:
"user_flags": {
"$uid": {
".write": "auth.uid == $uid",
".read": "auth.uid == $uid",
"liked": {
"$heroIdx": {
".validate": "newData.isString()"
}
}
}
}
在我的代码中,我想订阅 "liked heroes" ref,所以这就是我所做的:
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
import { AngularFireAuth } from 'angularfire2/auth';
@Injectable()
export class UserFlagsService {
likedHeroes$: Observable<string[]>;
constructor(
private afAuth: AngularFireAuth,
private db: AngularFireDatabase
) {
this.likedHeroes$ = afAuth.authState.flatMap(user => {
return user && user.uid
? this.db.list(`user_flags/${user.uid}/liked`)
.map(heroes => heroes.map(hero => <string>hero.$value))
: Observable.of([])
});
}
}
一切正常,直到用户注销...即使检查了 user
和 user.uid
,查询 user_flags/MY_ID_HERE/liked
似乎被触发了,我得到了 "permission denied".
我尝试使用 subscribe 和 watch for signout 来取消订阅,但它也不起作用...查询仍然被触发并失败 "permission denied"
我该如何处理?我希望我的服务 return 是一个可靠的可观察对象,这样我就可以在我的组件中订阅它。
非常感谢您的帮助
我设法通过创建 BehaviorSubject 并在触发 "signout" 之前取消订阅事件来使其工作。
这是我的供应商:
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Subscription } from 'rxjs/Subscription';
import { UserProvider } from '../../providers/user/user';
@Injectable()
export class UserFlagsProvider {
likedHeroes$: Observable<string[]>;
subHeroesLiked: Subscription;
constructor(
protected userProvider: UserProvider,
protected db: AngularFireDatabase
) {
const heroesLikedSubject: BehaviorSubject<string[]> = new BehaviorSubject([]);
this.likedHeroes$ = heroesLikedSubject.asObservable();
this.userProvider.user$.subscribe(user => {
if (user) {
this.subHeroesLiked = this.db.list(`user_flags/${user.uid}/liked`).subscribe(heroesSlugs => {
heroesLikedSubject.next(heroesSlugs.map(hero => <string>hero.$key));
});
}
});
this.userProvider.signingOut$.subscribe(() => {
this.subHeroesLiked.unsubscribe();
});
}
}
还有我的 userProvider
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { AngularFireAuth } from 'angularfire2/auth';
@Injectable()
export class UserProvider {
user$: Observable<firebase.User>;
user: firebase.User;
signingOut$: Subject<any> = new Subject();
constructor(private afAuth: AngularFireAuth) {
this.user$ = afAuth.authState;
this.user$.subscribe(user => this.user = user);
}
// [...]
signout() {
this.signingOut$.next();
return this.afAuth.auth.signOut();
}
}
希望对大家有所帮助。
仅供参考,由于未知原因,这不适用于 angularfire2-offline
。
如果有人看到更好的方法,我很感兴趣
我假设您想确保在视图中呈现的数据在注销时消失?
如果是这种情况,我建议使用 switchMap operator from RXJS 和以下模式:
this.userProvider = this.afAuth.authState;
this.likedHeroes$ = this.userProvider.switchMap((auth) => {
if(auth){
return this.af.list('user_flags/' + auth.uid + '/liked');
}
});
您需要添加以下内容以导入 switchMap 运算符:
import 'rxjs/add/operator/switchMap';
如果你想让我再补充一些,或者如果我对你想要实现的目标的假设不正确,请给我一些评论。我也一直在努力找出最好的方法来做这些事情。
您还应该从 Angular Firebase YouTube 查看 this video,它可能会帮助您解决问题中的一些问题。
我的用户可以喜欢英雄列表,所以我在我的 firebase 中有这个结构 rules/datas:
"user_flags": {
"$uid": {
".write": "auth.uid == $uid",
".read": "auth.uid == $uid",
"liked": {
"$heroIdx": {
".validate": "newData.isString()"
}
}
}
}
在我的代码中,我想订阅 "liked heroes" ref,所以这就是我所做的:
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
import { AngularFireAuth } from 'angularfire2/auth';
@Injectable()
export class UserFlagsService {
likedHeroes$: Observable<string[]>;
constructor(
private afAuth: AngularFireAuth,
private db: AngularFireDatabase
) {
this.likedHeroes$ = afAuth.authState.flatMap(user => {
return user && user.uid
? this.db.list(`user_flags/${user.uid}/liked`)
.map(heroes => heroes.map(hero => <string>hero.$value))
: Observable.of([])
});
}
}
一切正常,直到用户注销...即使检查了 user
和 user.uid
,查询 user_flags/MY_ID_HERE/liked
似乎被触发了,我得到了 "permission denied".
我尝试使用 subscribe 和 watch for signout 来取消订阅,但它也不起作用...查询仍然被触发并失败 "permission denied"
我该如何处理?我希望我的服务 return 是一个可靠的可观察对象,这样我就可以在我的组件中订阅它。
非常感谢您的帮助
我设法通过创建 BehaviorSubject 并在触发 "signout" 之前取消订阅事件来使其工作。 这是我的供应商:
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Subscription } from 'rxjs/Subscription';
import { UserProvider } from '../../providers/user/user';
@Injectable()
export class UserFlagsProvider {
likedHeroes$: Observable<string[]>;
subHeroesLiked: Subscription;
constructor(
protected userProvider: UserProvider,
protected db: AngularFireDatabase
) {
const heroesLikedSubject: BehaviorSubject<string[]> = new BehaviorSubject([]);
this.likedHeroes$ = heroesLikedSubject.asObservable();
this.userProvider.user$.subscribe(user => {
if (user) {
this.subHeroesLiked = this.db.list(`user_flags/${user.uid}/liked`).subscribe(heroesSlugs => {
heroesLikedSubject.next(heroesSlugs.map(hero => <string>hero.$key));
});
}
});
this.userProvider.signingOut$.subscribe(() => {
this.subHeroesLiked.unsubscribe();
});
}
}
还有我的 userProvider
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { AngularFireAuth } from 'angularfire2/auth';
@Injectable()
export class UserProvider {
user$: Observable<firebase.User>;
user: firebase.User;
signingOut$: Subject<any> = new Subject();
constructor(private afAuth: AngularFireAuth) {
this.user$ = afAuth.authState;
this.user$.subscribe(user => this.user = user);
}
// [...]
signout() {
this.signingOut$.next();
return this.afAuth.auth.signOut();
}
}
希望对大家有所帮助。
仅供参考,由于未知原因,这不适用于 angularfire2-offline
。
如果有人看到更好的方法,我很感兴趣
我假设您想确保在视图中呈现的数据在注销时消失?
如果是这种情况,我建议使用 switchMap operator from RXJS 和以下模式:
this.userProvider = this.afAuth.authState;
this.likedHeroes$ = this.userProvider.switchMap((auth) => {
if(auth){
return this.af.list('user_flags/' + auth.uid + '/liked');
}
});
您需要添加以下内容以导入 switchMap 运算符:
import 'rxjs/add/operator/switchMap';
如果你想让我再补充一些,或者如果我对你想要实现的目标的假设不正确,请给我一些评论。我也一直在努力找出最好的方法来做这些事情。
您还应该从 Angular Firebase YouTube 查看 this video,它可能会帮助您解决问题中的一些问题。