Angular 2 Route Guard可以根据Firebase用户角色进行激活

时间:2017-03-03 23:03:33

标签: angular firebase firebase-authentication rxjs

我一直花费数小时的时间在圈子里努力解决这个问题。我需要根据用户角色保护路由。

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";
}

}

这是来自主页组件的测试:

导出类HomeComponent实现OnInit {

authInfo: AuthInfo

constructor(private authService: AuthService) { }

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

}

这也有效但我无法弄清楚如何将其与CanActivate

联系起来

2 个答案:

答案 0 :(得分:2)

您需要使用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']);
      }
    });
}

在此示例中,将为具有角色&#34; GroupA&#34;的用户激活路线。

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

答案 1 :(得分:0)

除了@ 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']);
            }
        });

}