Javascript 如何在启动angular应用程序之前等待firebase验证
我想在firebase身份验证检索用户令牌时显示一个小的加载徽标,然后再启动“for real”单页应用程序 到目前为止,我有一个身份验证服务:Javascript 如何在启动angular应用程序之前等待firebase验证,javascript,angular,firebase,firebase-authentication,angularfire2,Javascript,Angular,Firebase,Firebase Authentication,Angularfire2,我想在firebase身份验证检索用户令牌时显示一个小的加载徽标,然后再启动“for real”单页应用程序 到目前为止,我有一个身份验证服务: constructor( public afAuth: AngularFireAuth, ) { this.afAuth.onAuthStateChanged(user => { if (user) { this.setCredentials(user) }
constructor(
public afAuth: AngularFireAuth,
) {
this.afAuth.onAuthStateChanged(user => {
if (user) {
this.setCredentials(user)
}
})
}
setCredentials(user: firebase.User) {
return user.getIdTokenResult(true).then(idTokenResult => {
this.credentials = {
userId: idTokenResult.claims.id,
role: idTokenResult.claims.role,
token: idTokenResult.token,
};
// STARTS THE APPLICATION NOW ?
})
}
有可能实现这样的行为吗?我读过关于APP_初始化器的文章,但没有成功。我希望避免本地存储/会话存储,而只依赖于此初始化
更新:
创建了一个init函数:
export function initApp(auth: AuthService, afAuth: AngularFireAuth) {
return () => {
return new Promise((resolve) => {
afAuth.user.pipe(
take(1),
).subscribe(user => {
if (user) {
auth.setCredentials(user)
.then(() => resolve())
} else {
resolve();
}
})
});
}
}
和编辑的AppModule提供程序:
providers: [
interceptorProviders /* my interceptors */,
{
provide: APP_INITIALIZER,
useFactory: initApp,
deps: [AuthService, AngularFireAuth],
multi: true
}
]
仍然需要弄清楚如何添加等待标识,但这是另一个问题。我会尽快更新。您应该在
CanActivate
路由器保护中使用身份验证服务:
这意味着您的AppModule将首先加载,然后您的子路由(例如,路由器路径为“”的MainModule)具有保护。然后,在AppModule中,您可以检查服务的状态并显示加载信息,直到MainModule被激活(当firebase身份验证完成时)您应该在
CanActivate
路由器保护中使用您的身份验证服务:
这意味着您的AppModule将首先加载,然后您的子路由(例如,路由器路径为“”的MainModule)具有保护。然后在AppModule中,您可以检查服务的状态并显示加载信息,直到MainModule被激活(当firebase auth完成时)回答我自己的问题 总之,我希望在处理路由之前,确保与firebase用户关联的令牌声明(角色和用户id)存储在我的身份验证服务中,因为这些路由中的组件将使用这些凭据 最后,我没有遵循APP_初始值设定项,这不是一个好的解决方案 身份验证服务
private _credentials: BehaviorSubject<Credentials> = new BehaviorSubject<Credentials>(null);
public readonly credentials$: Observable<Credentials> = this._credentials.asObservable();
constructor(private afAuth: AngularFireAuth) {
this.afAuth.authState.subscribe(user => {
this._credentials.next(null);
if (user) {
user.getIdTokenResult().then(data => {
const credentials = {
role: data.claims.role,
token: data.token,
userId: data.claims.userId
}
this._credentials.next(credentials);
console.log(credentials);
})
} else {
this._credentials.next({role: null, token: null, userId: null});
}
})
}
get credentials(): Credentials {
return this._credentials.value;
}
private\u凭证:BehaviorSubject=newbehaviorsubject(null);
public readonly credentials$:Observable=此。_credentials.asObservable();
构造函数(专用afAuth:AngularFireAuth){
this.afAuth.authState.subscribe(用户=>{
此.\u凭证.next(空);
如果(用户){
user.getIdTokenResult().then(数据=>{
常量凭据={
角色:data.claims.role,
token:data.token,
userId:data.claims.userId
}
此.\u凭据。下一步(凭据);
控制台日志(凭证);
})
}否则{
this.\u credentials.next({role:null,token:null,userId:null});
}
})
}
获取凭据():凭据{
返回此。\u credentials.value;
}
在app.component中显示等待的微调器
如果未设置凭据,下面将阻止显示路由。
在模板中:
<div *ngIf="!(credentials$ | async)" class="logged-wrapper">
<div class="spinner-wrapper">
<mat-spinner class="spinner"></mat-spinner>
</div>
</div>
<router-outlet *ngIf="(credentials$ | async)"></router-outlet>
在组件中:
credentials$: Observable<any>;
constructor(
private auth: AuthService,
) {
this.credentials$ = this.auth.credentials$;
}
凭证$:可观察;
建造师(
私有身份验证:身份验证服务,
) {
this.credentials$=this.auth.credentials$;
}
验证保护
takewhile允许我在继续之前确保设置了凭据
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot):Promise<boolean> {
return new Promise((resolve) => {
this.auth.credentials$.pipe(
takeWhile(credentials => credentials === null),
).subscribe({
complete: () => {
const credentials = this.auth.credentials
if (!credentials.role) {
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } })
resolve(false);
}
if (next.data.roles && next.data.roles.indexOf(credentials.role) === -1) {
this.router.navigate(['/']);
resolve(false);
}
resolve(true)
}
})
})
}
canActivate(下一步:ActivatedRouteSnapshot,状态:RouterStateSnashot):承诺{
返回新承诺((解决)=>{
此.auth.credentials$.pipe(
takeWhile(凭证=>凭证===null),
).订阅({
完成:()=>{
const credentials=this.auth.credentials
如果(!credentials.role){
this.router.navigate(['/login'],{queryParams:{returnUrl:state.url}})
决议(假);
}
if(next.data.roles&&next.data.roles.indexOf(credentials.role)=-1){
this.router.navigate(['/']);
决议(假);
}
解析(真)
}
})
})
}
回答我自己的问题
总之,我希望在处理路由之前,确保与firebase用户关联的令牌声明(角色和用户id)存储在我的身份验证服务中,因为这些路由中的组件将使用这些凭据
最后,我没有遵循APP_初始值设定项,这不是一个好的解决方案
身份验证服务
private _credentials: BehaviorSubject<Credentials> = new BehaviorSubject<Credentials>(null);
public readonly credentials$: Observable<Credentials> = this._credentials.asObservable();
constructor(private afAuth: AngularFireAuth) {
this.afAuth.authState.subscribe(user => {
this._credentials.next(null);
if (user) {
user.getIdTokenResult().then(data => {
const credentials = {
role: data.claims.role,
token: data.token,
userId: data.claims.userId
}
this._credentials.next(credentials);
console.log(credentials);
})
} else {
this._credentials.next({role: null, token: null, userId: null});
}
})
}
get credentials(): Credentials {
return this._credentials.value;
}
private\u凭证:BehaviorSubject=newbehaviorsubject(null);
public readonly credentials$:Observable=此。_credentials.asObservable();
构造函数(专用afAuth:AngularFireAuth){
this.afAuth.authState.subscribe(用户=>{
此.\u凭证.next(空);
如果(用户){
user.getIdTokenResult().then(数据=>{
常量凭据={
角色:data.claims.role,
token:data.token,
userId:data.claims.userId
}
此.\u凭据。下一步(凭据);
控制台日志(凭证);
})
}否则{
this.\u credentials.next({role:null,token:null,userId:null});
}
})
}
获取凭据():凭据{
返回此。\u credentials.value;
}
在app.component中显示等待的微调器
如果未设置凭据,下面将阻止显示路由。
在模板中:
<div *ngIf="!(credentials$ | async)" class="logged-wrapper">
<div class="spinner-wrapper">
<mat-spinner class="spinner"></mat-spinner>
</div>
</div>
<router-outlet *ngIf="(credentials$ | async)"></router-outlet>
在组件中:
credentials$: Observable<any>;
constructor(
private auth: AuthService,
) {
this.credentials$ = this.auth.credentials$;
}
凭证$:可观察;
建造师(
私有身份验证:身份验证服务,
) {
this.credentials$=this.auth.credentials$;
}
验证保护
takewhile允许我在继续之前确保设置了凭据
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot):Promise<boolean> {
return new Promise((resolve) => {
this.auth.credentials$.pipe(
takeWhile(credentials => credentials === null),
).subscribe({
complete: () => {
const credentials = this.auth.credentials
if (!credentials.role) {
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } })
resolve(false);
}
if (next.data.roles && next.data.roles.indexOf(credentials.role) === -1) {
this.router.navigate(['/']);
resolve(false);
}
resolve(true)
}
})
})
}
canActivate(下一步:ActivatedRouteSnapshot,状态:RouterStateSnashot):承诺{
返回新承诺((解决)=>{
此.auth.credentials$.pipe(
takeWhile(凭证=>凭证===null),
).订阅({
完成:()=>{
const credentials=this.auth.credentials
如果(!credentials.role){
this.router.navigate(['/login'