
[英]How to add document to Firestore and return Observable<T>
[英]How to make an observer to return as observable?
我是rxjs的新手,想要解决这个问题。
我想将一个Observer
传递给onAuthStateChanged()
,它接受一个观察者对象。 观察者会做一些工作并发出一个布尔值,以便布尔值可以作为Observable
返回。 我如何实现从可观察到观察者的这个桥梁?
export class AuthGuard implements CanActivate {
constructor(private firebase: FirebaseService, private router: Router) {
}
canActivate(): Observable<boolean> {
this.firebase.auth.onAuthStateChanged(/* an observer */)
return /* an Observable<boolean> */
}
}
由于onAuthStateChanged
将一个观察者作为输入,并返回拆解函数,我们可以简单地用它包装:
Rx.Observable.create(obs => firebase.auth().onAuthStateChanged(obs))
实际上由于奇怪的原因,这可能不起作用,我们可以这样做:
var onAuthStateChanged$ = Rx.Observable.create(obs => {
return firebase.auth().onAuthStateChanged(
user => obs.next(user),
err => obs.error(err),
() => obs.complete());
})
现在,如果你不熟悉Observable.create
函数,让我解释一下: create
接受一个onSubscribe
函数,该函数交给一个观察者并返回拆解函数。 对现在onAuthStateChanged
听起来非常熟悉的是什么? 你交了nextOrObserver
,它就会返回拆解!
(现在由于奇怪的原因, nextOrObserver
不接受我的observer
,所以我转而给它next
函数.Hench上面的代码。)
设置onAuthStateChanged$
后,我们可以使用运算符转换流。 所有操作符都将一个observable转换为另一个,而RxJs有几十个。 在您的情况下,它可能看起来像这样:
canActivate(): Observable<boolean> {
onAuthStateChanged$
.do(user => {if (!user) { this.router.navigate(['/login']); } })
.map(user => !!user)
.do(user => console.log('Authenticated?', user))
}
为了让别人受益,这就是我最后写的东西,它似乎运作良好。
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';
import { Observable } from 'rxjs/Observable';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { FirebaseService } from '../shared/firebase.service';
@Injectable()
export class AuthGuard implements CanActivate {
loggedInSubject: ReplaySubject<any>;
constructor(private firebase: FirebaseService, private router: Router) {
this.loggedInSubject = new ReplaySubject(1);
this.firebase.auth.onAuthStateChanged(this.loggedInSubject);
}
canActivate(): Observable<boolean> {
return this.loggedInSubject.map(user => {
if (!user) {
this.router.navigate(['/login']);
}
console.log('Authenticated?', !!user);
return !!user;
}).take(1);
}
}
这是短版本,你可以放在任何地方的辅助功能......
export function MakeAuthstateObservable(
auth: firebase.auth.Auth
): Observable<firebase.User> {
const authState = Observable.create((observer: Observer<firebase.User>) => {
auth.onAuthStateChanged(
(user?: firebase.User) => observer.next(user),
(error: firebase.auth.Error) => observer.error(error),
() => observer.complete()
);
});
return authState;
}
类似方法:
./auth-guard.ts
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { AuthService } from '../shared/auth.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private router: Router,
private authService: AuthService) { }
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.authState.map((auth) => {
if (auth == null) {
this.router.navigate(['auth']);
return false;
} else {
return true;
}
}).first();
}
}
./shared/auth.service.ts
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { FirebaseApp } from '../shared/firebase';
@Injectable()
export class AuthService {
public auth: firebase.auth.Auth;
public authState: Observable<firebase.User>;
constructor(public app: FirebaseApp) {
this.auth = app.auth();
this.authState = this.authStateObservable(app);
}
/**
* @function
* @desc Create an Observable of Firebase authentication state
*/
public authStateObservable(app: FirebaseApp): Observable<firebase.User> {
const authState = Observable.create((observer: Observer<firebase.User>) => {
this.auth.onAuthStateChanged(
(user?: firebase.User) => observer.next(user),
(error: firebase.auth.Error) => observer.error(error),
() => observer.complete()
);
});
return authState;
}
}
./shared/firebase.ts
import * as firebase from 'firebase';
export class FirebaseApp implements firebase.app.App {
name: string;
options: {};
auth: () => firebase.auth.Auth;
database: () => firebase.database.Database;
messaging: () => firebase.messaging.Messaging;
storage: () => firebase.storage.Storage;
delete: () => firebase.Promise<any>;
constructor() {
return firebase.initializeApp({
apiKey: 'AIzaSyC6pDjAGuqXtVsU15erxVT99IdB0t4nln4',
authDomain: 'inobrax-ebs-16552.firebaseapp.com',
databaseURL: 'https://inobrax-ebs-16552.firebaseio.com',
storageBucket: 'inobrax-ebs-16552.appspot.com',
messagingSenderId: '383622803653'
});
}
}
不确定这是否必然比上面的答案“更好”,但它肯定更清洁。 我决定在AuthService
上创建两个属性,一个只是一个布尔值来反映用户是否经过身份验证,一个userLoggedIn
主题基本上发出了布尔属性的值。 这两个属性都与onAuthStateChanged()
绑定。 因此,一旦状态发生更改,经过authenticated
属性将变为true,否则userLoggedIn
false, userLoggedIn
使用next()
( next(this.authenticated)
)发出此值。 在AuthGuard
我设置CanActivate()
以返回boolean
或Observable<boolean>
。 首先,如果检查了AuthService
上的authenticated
属性,并且它返回true,否则它映射userLoggedIn
主题以查明用户是否已经过身份验证。 这意味着在页面刷新后,guard将返回已发出主题的值,因为尚未定义authenticated
,因此只需等待userLoggedIn
返回。 首先检查经过authenticated
属性的原因是,如果您尝试使用nav链接更改页面,则不会发生任何事情,因为guard仅返回主题的发出值,仅在授权状态更改时调用 - 即登录,注销或页面刷新(重新引导应用程序)。 代码如下:
AuthService
import * as firebase from 'firebase';
import { Router } from '@angular/router';
import { Injectable, OnInit } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class AuthService implements OnInit {
authenticated: boolean;
userLoggedIn = new Subject<boolean>();
constructor(private router: Router) {}
ngOnInit() {
}
checkAuthStatus() {
firebase.auth().onAuthStateChanged((user) => {
this.authenticated = !!user;
this.userLoggedIn.next(this.authenticated);
});
}
login(email: string, password: string) {
firebase.auth().signInWithEmailAndPassword(email, password).then(() => {
this.authenticated = true;
this.router.navigate(['/']);
}).catch((error) => {
console.log(error);
});
}
logout() {
firebase.auth().signOut().then(function() {
this.router.navigate(['login']);
}.bind(this)).catch((error) => {
console.log(error);
});
}
}
AuthGuard
import { CanActivate, Router } from '@angular/router';
import { Injectable } from '@angular/core';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {
}
canActivate(): Observable<boolean> | boolean {
if(this.authService.authenticated) {
return true;
}
return this.authService.userLoggedIn.map((authenticated) => {
if(!authenticated) {
this.router.navigate(['login']);
}
return authenticated;
});
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.