【问题标题】:Angular 2 Route Guard CanActivate based on Firebase User RoleAngular 2 Route Guard CanActivate 基于 Firebase 用户角色
【发布时间】:2017-07-24 05:09:39
【问题描述】:

我一直在兜圈子,试图弄清楚这一点。我需要根据用户角色保护路由。

constructor(private af: AngularFire, private db: AngularFireDatabase, private router: Router, private auth: AngularFireAuth) {

    af.auth.subscribe(user => {

        if (user) {
            this.getUserRole(user);
        } else {
            console.log('no user');
        }

    });

}

这至少得到了角色:

 getUserRole(user): any {

  this.db.list('users', {
        query: {
            orderByKey: true,
            equalTo: user.uid
        }
    }).subscribe(user => console.log(user[0].role));

}

这是一个基于用户是否登录的有效 CanActivate,但显然角色无关紧要。

canActivate(route:ActivatedRouteSnapshot,
            state:RouterStateSnapshot):Observable<boolean> {

            return this.af.auth.take(1)
        .map(authSate => !!authSate)
        .do( authenticated => {
            console.log(authenticated)
            if (!authenticated)
            this.router.navigate(['/login'])
        })

}

我不知道如何考虑用户角色。我的设置非常基本......它的/users/$uid/role。

这是我尝试过的其他方法:

导出类 AuthService {

static UNKNOWN_USER = new AuthInfo(null, null);

authInfo$: BehaviorSubject<AuthInfo> = new BehaviorSubject<AuthInfo>(AuthService.UNKNOWN_USER);

constructor(private af: AngularFire, private db: AngularFireDatabase, private router: Router, private auth: AngularFireAuth) {

    af.auth.subscribe(user => {

        if (user) {

            let getRole = this.db.list('users', {
                query: {
                    orderByKey: true,
                    equalTo: user.uid
                }
            }).subscribe(snap => {
                if (snap.length === 0) {
                    return;
                } else {
                    let role = "";
                    role = snap[0].role
                    const authInfo = new AuthInfo(user.uid, role);
                    this.authInfo$.next(authInfo);
                }
            });

        } else {
            console.log('no user');
        }

    });

}

这里是 AuthInfo 类:

导出类 AuthInfo {

constructor(public $uid: string, public role: string) { }

isLoggedIn() {
    console.log('from authinfo', !!this.$uid)
    //tells us if user is logged in or not
    return !!this.$uid;
}

isGroupALoggedIn() {
    //tells us if user is logged in or not
    return !!this.$uid && this.role === "GroupA";
}

isGroupBLoggedIn() {
    //tells us if user is logged in or not
    return !!this.$uid && this.role === "GroupB";
}

}

这是来自 Home 组件的测试:

导出类 HomeComponent 实现 OnInit {

authInfo: AuthInfo

constructor(private authService: AuthService) { }

ngOnInit() {
    //returns boolean
    this.authService.authInfo$.subscribe(authInfo => {
        console.log(authInfo);
        this.authInfo = authInfo
    });
}

}

这也可以,但我不知道如何将它与 CanActivate 联系起来

【问题讨论】:

    标签: angular firebase firebase-authentication rxjs


    【解决方案1】:

    您需要使用mergeMap() 运算符链接两个可观察对象——一个获取用户,一个获取用户角色。

    将所有这些代码放在 canActivate 挂钩中。

    canActivate(): Observable<boolean> {
      return af.auth
        .mergeMap(user =>
          // Extract the role from userData if user exists, or empty string if no user.
          user ? getUserRole(user).map(userData => userData[0].role) : Observable.of('')
        )
        // Transform the role into true or false
        // since this is what canActivate() must return.
        .map({
          if (userRole === "GroupA") {
            return true;
          } else {
            this.router.navigate(['/login']);
          }
        });
    }
    

    在本例中,将为角色为“GroupA”的用户激活路由。

    更新:根据 dhndeveloper 要求,检查是否存在用户 + 重定向(如果没有允许的角色)。

    【讨论】:

    • 这太棒了!!谢谢!!
    • 我如何确保在这个可观察链中首先存在用户?如果 af.auth 没有返回用户怎么办?
    • 我想我明白了,见下文。
    • 正确。我更新了我的答案以供将来参考。小注:由于mergeMap返回角色作为字符串你应该返回Observable.of('')(空字符串)以保持一致性。
    • 我正在尝试做同样的事情,但我有 this.auth.mergeMap is not a function 错误。有人知道为什么会这样吗?
    【解决方案2】:

    除了@AngularFrance 的解决方案之外,只需要检查用户是否存在:

    canActivate(route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean> {
    
        return this.af.auth
            .mergeMap(user => {
                if (user) {
                    // Extract the role from userData
                    return this.authService.getUserRole(user).map(userData => userData[0].role)
                } else {
                    return Observable.of({});
                }
    
            })
            // Transform the role into true or false
            // since this is what canActivate() must return.
            .map(userRole => {
                if (userRole === "GroupA") {
                    return true;
                } else {
                    this.router.navigate(['/login']);
                }
            });
    
    }
    

    【讨论】:

      猜你喜欢
      • 2018-03-18
      • 1970-01-01
      • 1970-01-01
      • 2017-07-16
      • 2019-02-05
      • 1970-01-01
      • 2017-10-21
      • 2017-05-11
      • 2019-09-22
      相关资源
      最近更新 更多