我是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> */
}
}
答案 0 :(得分:4)
由于private static Customer[] GetCustomers(IElasticClient elasticClient)
{
var customers = new List<Customer>();
var searchResult = elasticClient.Search<Customer>(s => s.Index(IndexAlias.ForCustomers())
.Size(10000).SearchType(SearchType.Scan).Scroll("1m"));
do
{
var result = searchResult;
searchResult = elasticClient.Scroll<Customer>("1m", result.ScrollId);
customers.AddRange(searchResult.Documents);
} while (searchResult.IsValid && searchResult.Documents.Any());
return customers.ToArray();
}
将观察者作为输入,并返回拆解功能,我们可以简单地用以下内容包装:
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
功能.Hench上面的代码。)
设置next
后,我们可以使用运算符转换流。所有操作符都将一个observable转换为另一个,而RxJs有几十个。在您的情况下,它可能如下所示:
onAuthStateChanged$
答案 1 :(得分:3)
为了让别人受益,这就是我最后写的东西,而且似乎运作良好。
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);
}
}
答案 2 :(得分:1)
这是简短的版本,您可以将其放置在任何地方的辅助功能...
code
答案 3 :(得分:0)
类似方法:
./ 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();
}
}
./共享/ 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;
}
}
./共享/ 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'
});
}
}
答案 4 :(得分:0)
不确定这是否必须更好&#39;比上面的答案,但它肯定更清洁。我决定在AuthService
上创建两个属性,一个只是一个布尔值来反映用户是否经过身份验证,一个userLoggedIn
主题基本上发出了布尔属性的值。这两个属性都与onAuthStateChanged()
绑定。因此,一旦状态发生变化,authenticated
属性变为true,如果经过身份验证,则为false,userLoggedIn
使用next()
(next(this.authenticated)
)发出此值。在AuthGuard
我设置CanActivate()
以返回boolean
或Observable<boolean>
。首先,如果选中authenticated
上的AuthService
属性,并且返回true,否则它会映射userLoggedIn
主题以确定用户是否已经过身份验证。这意味着在页面刷新后,后卫将返回已发出主题的值,因为尚未定义authenticated
,因此只需等待userLoggedIn
返回。首先检查authenticated
属性的原因是,如果您尝试使用导航链接更改页面,则不会发生任何事情,因为保护仅返回主题的发射值,仅在状态为授权更改 - 即登录,注销或页面刷新(重新引导应用程序)。代码如下:
<强> 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;
});
}
}