如何使观察者以可观察的方式返回?

时间:2016-08-23 23:52:02

标签: firebase rxjs firebase-authentication

我是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> */
    }
}

5 个答案:

答案 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()以返回booleanObservable<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;
        });
    }
}