我正在尝试使用Angularfire2和Angular4为学校作业构建基于角色的授权。但是,当我刷新页面时,我会重定向到登录页面,因为在Angularfire从Firebase数据库获取用户(+角色)之前,Guard会执行。 我想让最终用户重新加载页面而不会被重定向到登录页面。
我搜索了很多网站,但找不到任何有用的东西。许多站点解释了如何支持重新加载但不使用用户角色(因此没有Firebase数据库查询),而其他站点解释了如何使用多个用户角色但不支持页面重新加载。
我的(相关)代码:
auth.service.ts :
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
import { User } from '../models/user.model';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/take';
@Injectable()
export class AuthService {
user: BehaviorSubject<User> = new BehaviorSubject(null);
constructor (private afAuth: AngularFireAuth, private db: AngularFireDatabase) {
this.afAuth.authState
.switchMap(auth => {
console.log(auth);
if (auth) {
/// signed in
return this.db.object('users/' + auth.uid);
} else {
/// not signed in
return Observable.of(null);
}
})
.subscribe(user => {
this.user.next(user);
});
}
googleLogin () {
const provider = new firebase.auth.GoogleAuthProvider();
return this.afAuth.auth.signInWithPopup(provider)
.then(credential => {
return this.updateUser(credential.user);
});
}
signOut () {
return this.afAuth.auth.signOut();
}
private updateUser (authData) {
const userData = new User(authData);
const ref = this.db.object('users/' + authData.uid);
return ref.take(1).subscribe(user => {
if (!user.name) {
ref.update(userData);
}
});
}
}
guard.ts :
import {Injectable} from '@angular/core';
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router} from '@angular/router';
import {Observable} from 'rxjs/Observable';
import {AuthService} from '../shared/services/auth.service';
import * as _ from 'lodash';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';
@Injectable()
export class AdminGuard implements CanActivate {
constructor (private auth: AuthService, private router: Router) {}
canActivate (next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
return this.auth.user
.take(1)
.map(user => _.get(_.get(user, 'roles'), 'admin'))
.do(authorized => {
if (!authorized) {
this.router.navigate(['/login']);
}
});
}
}
提前致谢!
答案 0 :(得分:0)
我假设您正在将服务和警卫导入您的AppModule(如果您将其导入CoreModule也很好,但我的建议还需要额外的工序)。
无论哪种方式,除非您将服务注入/传递到AppModule的构造函数中,否则您的服务不会被创建/实例化,直到AdminGuard首次调用它为止。考虑到这一点,您可以为canActivate功能进行订阅以及未及时运行(它是异步事件),尤其是考虑到您正在进行第一次输出。
重点是你应该将服务注入Module构造函数。