在重定向之前,AngularFire Auth 将 FireBase 令牌交换为我的平台令牌
AngularFire Auth exchange FireBase token for my platform's token before re-direct
我正在使用 AngularFire 来促进对 Firebase Auth 用户池的身份验证,身份验证工作正常。
但是,在 Firebase 身份验证之后和从登录页面重定向到我受保护的 Web 应用程序页面之一之前,我需要从我的平台将 Firebase 令牌交换为 JWT 令牌。
我认为执行此操作的方法是在 router guard.
中实现调用我的平台令牌 API 的逻辑
然而,当我这样做时,我得到这个错误:
TypeError: source.lift is not a function
这是我的 app-routing.module.ts
,如果我将 switchMap
替换为 map
并删除 async/await
(不要将其设为 return 承诺或执行异步逻辑在回调中)一切正常 - 但是我没有打电话给我 API.
import { NgModule, Injector } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { canActivate, redirectUnauthorizedTo, redirectLoggedInTo } from '@angular/fire/auth-guard';
import { switchMap } from 'rxjs/operators';
import * as firebase from 'firebase';
import { LoginComponent } from './login/login.component';
import { InvestconfigComponent } from './investconfig/investconfig.component';
import { setWebIdentityCredentials } from './shared/auth.service';
//THIS IS THE IMPORTANT method
const redirectLoggedInAferSetAwsCreds = switchMap(async (user: firebase.User) => {
// Call off to my backend to exchange FBase token for platform token..
await setWebIdentityCredentials(user);
return user ? ['config'] : true;
});
const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['login']);
const routes: Routes = [
{ path: '', redirectTo: '/config', pathMatch: 'full' },
{ path: 'login', component: LoginComponent, ...canActivate(redirectLoggedInAferSetAwsCreds) },
{ path: 'config', component: InvestconfigComponent, ...canActivate(redirectUnauthorizedToLogin) },
{ path: '**', redirectTo: '/config' },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
为什么这行不通?有没有更好的方法来解决我的问题?
我让它工作了,但是当 AngularFire auth guards 被调用时我完全误解了。海事组织,你不应该为了在你的守卫中获得信誉而大声疾呼。
如果您需要 await 承诺,这里是可以工作的守卫:
const guardAndSetAwsCreds = pipe(
tap(async (user: firebase.User) => {
await setWebIdentityCredentials(user);
}),
map((user: firebase.User) => {
return user ? true : ['login'];
}),
);
tap()
不会产生副作用,并将原始对象(在本例中为 user
)传递到 map()
.
我的错误印象是,当 AuthFire 身份验证方法成功完成时,AuthFire 守卫是通过订阅调用的。事实并非如此。这是 AuthFire auth method
:
的示例
this.afAuth.auth.signInWithEmailLink(email, window.location.href)
因为我不再有时间问题,所以我只是在我的登录方法中调用以获取平台令牌:
async signinWithEmailLink() {
// Confirm the link is a sign-in with email link.
if (this.afAuth.auth.isSignInWithEmailLink(window.location.href)) {
// Additional state parameters can also be passed via URL.
// This can be used to continue the user's intended action before triggering
// the sign-in operation.
// Get the email if available. This should be available if the user completes
// the flow on the same device where they started it.
let email = window.localStorage.getItem('emailForSignIn');
if (!email) {
// User opened the link on a different device. To prevent session fixation
// attacks, ask the user to provide the associated email again. For example:
email = window.prompt('Please provide your email for confirmation');
}
// The client SDK will parse the code from the link for you.
const res = await this.afAuth.auth.signInWithEmailLink(email, window.location.href)
window.localStorage.removeItem('emailForSignIn');
if (res.additionalUserInfo.isNewUser) {
//User does NOT already exist in system (added by admin) might be sign-up from random dude from internet
throw new Error('An admin must add you first');
}
await setWebIdentityCredentials(res.user);
}
}
我的路由守卫现在超级简单:
const routes: Routes = [
{ path: '', redirectTo: '/config', pathMatch: 'full' },
{ path: 'login', component: LoginComponent, ...canActivate(redirectLoggedInTo(['config'])) },
{ path: 'config', component: InvestconfigComponent, ...canActivate(redirectUnauthorizedTo(['login'])) },
{ path: '**', redirectTo: '/config' },
];
我正在使用 AngularFire 来促进对 Firebase Auth 用户池的身份验证,身份验证工作正常。
但是,在 Firebase 身份验证之后和从登录页面重定向到我受保护的 Web 应用程序页面之一之前,我需要从我的平台将 Firebase 令牌交换为 JWT 令牌。
我认为执行此操作的方法是在 router guard.
中实现调用我的平台令牌 API 的逻辑然而,当我这样做时,我得到这个错误:
TypeError: source.lift is not a function
这是我的 app-routing.module.ts
,如果我将 switchMap
替换为 map
并删除 async/await
(不要将其设为 return 承诺或执行异步逻辑在回调中)一切正常 - 但是我没有打电话给我 API.
import { NgModule, Injector } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { canActivate, redirectUnauthorizedTo, redirectLoggedInTo } from '@angular/fire/auth-guard';
import { switchMap } from 'rxjs/operators';
import * as firebase from 'firebase';
import { LoginComponent } from './login/login.component';
import { InvestconfigComponent } from './investconfig/investconfig.component';
import { setWebIdentityCredentials } from './shared/auth.service';
//THIS IS THE IMPORTANT method
const redirectLoggedInAferSetAwsCreds = switchMap(async (user: firebase.User) => {
// Call off to my backend to exchange FBase token for platform token..
await setWebIdentityCredentials(user);
return user ? ['config'] : true;
});
const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['login']);
const routes: Routes = [
{ path: '', redirectTo: '/config', pathMatch: 'full' },
{ path: 'login', component: LoginComponent, ...canActivate(redirectLoggedInAferSetAwsCreds) },
{ path: 'config', component: InvestconfigComponent, ...canActivate(redirectUnauthorizedToLogin) },
{ path: '**', redirectTo: '/config' },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
为什么这行不通?有没有更好的方法来解决我的问题?
我让它工作了,但是当 AngularFire auth guards 被调用时我完全误解了。海事组织,你不应该为了在你的守卫中获得信誉而大声疾呼。
如果您需要 await 承诺,这里是可以工作的守卫:
const guardAndSetAwsCreds = pipe(
tap(async (user: firebase.User) => {
await setWebIdentityCredentials(user);
}),
map((user: firebase.User) => {
return user ? true : ['login'];
}),
);
tap()
不会产生副作用,并将原始对象(在本例中为 user
)传递到 map()
.
我的错误印象是,当 AuthFire 身份验证方法成功完成时,AuthFire 守卫是通过订阅调用的。事实并非如此。这是 AuthFire auth method
:
this.afAuth.auth.signInWithEmailLink(email, window.location.href)
因为我不再有时间问题,所以我只是在我的登录方法中调用以获取平台令牌:
async signinWithEmailLink() {
// Confirm the link is a sign-in with email link.
if (this.afAuth.auth.isSignInWithEmailLink(window.location.href)) {
// Additional state parameters can also be passed via URL.
// This can be used to continue the user's intended action before triggering
// the sign-in operation.
// Get the email if available. This should be available if the user completes
// the flow on the same device where they started it.
let email = window.localStorage.getItem('emailForSignIn');
if (!email) {
// User opened the link on a different device. To prevent session fixation
// attacks, ask the user to provide the associated email again. For example:
email = window.prompt('Please provide your email for confirmation');
}
// The client SDK will parse the code from the link for you.
const res = await this.afAuth.auth.signInWithEmailLink(email, window.location.href)
window.localStorage.removeItem('emailForSignIn');
if (res.additionalUserInfo.isNewUser) {
//User does NOT already exist in system (added by admin) might be sign-up from random dude from internet
throw new Error('An admin must add you first');
}
await setWebIdentityCredentials(res.user);
}
}
我的路由守卫现在超级简单:
const routes: Routes = [
{ path: '', redirectTo: '/config', pathMatch: 'full' },
{ path: 'login', component: LoginComponent, ...canActivate(redirectLoggedInTo(['config'])) },
{ path: 'config', component: InvestconfigComponent, ...canActivate(redirectUnauthorizedTo(['login'])) },
{ path: '**', redirectTo: '/config' },
];