【问题标题】:User access for specific routes with parameters带有参数的特定路由的用户访问
【发布时间】:2018-07-07 12:20:23
【问题描述】:

我正在使用 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 :) 我希望我只是澄清我想要实现的目标。如果您仍然感到困惑,请在 cmets 中告诉我。

有什么问题?

在我的项目中这很好用,但问题是当有人将不同项目的 id 复制到 url 并点击输入时。我想阻止用户访问其他用户的项目,所以如果我在 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 或布尔值...

问题

我对这个特定问题的一般方法是否正确?我应该考虑一些更好的选择吗?其他页面如何解决这个问题,例如firebase(试试这个Firebase)。如果我的解决方案很好,你能帮我解决我的 project.guard 吗?非常感谢

我试图尽可能清楚地描述我的问题。如果您遗漏了一些信息,请在 cmets 中告诉我,我会更新我的问题。我搜索了很多小时如何解决这个问题,但我找不到任何东西,或者我只是使用了错误的搜索关键字。我希望这对其他人也有帮助。

【问题讨论】:

    标签: angular firebase rxjs angularfire2 angular-guards


    【解决方案1】:

    当您看到Observables 时,您可以确定(几乎)有两件事您做错了:

    1. 做一个嵌套的subscribe,并且
    2. 将结果分配给subsrciption aka var result == someObservables.subscribe()

    这正是你在代码中犯的两个错误。

    发生错误 1 ​​的原因是因为大多数时候Observables 是异步的,这也是您的情况,您的代码无法确保返回结果的顺序。您的代码同步运行,不能故意等待异步任务的执行。这就是 operators 存在的原因(映射、过滤器、concatMap 等),以便您处理 Observables(本身),而不是在 Observables 最终发出其值时在订阅内部。

    错误 2 并不少见,因为对于 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);
            });
    }
    

    上面的代码所做的是它结合了两个 Observables,this.itemDoc.valueChangesthis.auth.user。但是角度路由器保护需要Observable&lt;boolean&gt;,因此您需要映射它们以便将其转换为布尔值。

    如果你使用的是 rxjs 6,语法略有不同:

    return combineLatest(this.itemDoc.valueChanges, this.authU.user)
        .pipe(
            map(([response, authUser]) => {
                return response.users.any(x => x.userID === authUser.uid);
            })
        );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-31
      • 1970-01-01
      • 2021-03-20
      • 2019-06-14
      • 2014-03-14
      • 2014-12-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多