angular - 确保在发出下一个值之前发生订阅的最佳方法
问题描述
我正在使用 OAuth 2.0 在我的 Angular 应用程序中为我的用户检索令牌。我使用流行的库angular-oauth2-oidc
来处理 OAuth 流。因此,在我的 AppComponent 中,我设置了 oAuthService angular-oauth2-oidc
,然后通过调用在我的登录组件中启动 oAuth 流程initCodeFlow()
。用户被重定向以输入他的凭据,然后他被重定向到我,我在 AppComponent 中收到令牌并将其作为下一个令牌放入我的 DataService TokenSubject。
但现在我想在 MainPageComponent 的标头中使用该令牌进行 API 调用。所以我在我的 MainPage 中订阅了 TokenSubject,当我收到 Token 时,订阅块中的代码就会执行。
但是,如果令牌 get 发送给我的速度比主页面构建的速度快怎么办?然后,当 AppComponent 发出下一个 Token 值时,我还没有订阅 Main Page 中的 TokenSubject。我不确定,但我的主页有时没有打开,我认为这可能是原因。
在发出 TokenSubject 之前,确保主页订阅 TokenSubject 的最佳方法是什么?
我的AppComponent
:
import { OAuthService } from 'angular-oauth2-oidc';
...
export class AppComponent implements OnInit {
token: Token = {
access_token: null,
refresh_token: null
};
constructor(private oauthService: OAuthService,
private adapterService: AdapterService,
private dataService: DataService,
private logger: NGXLogger) {
}
ngOnInit() {
this.configureOAuthService();
this.subscribeToOAuthEvents();
}
configureOAuthService() {
const authConfig: AuthConfig = {
issuer: environment.oauthLoginUrl,
redirectUri: environment.oauthRedirectUrl,
clientId: environment.apiKey,
scope: 'openid',
responseType: 'code',
showDebugInformation: true,
disablePKCE: false,
oidc: true,
disableAtHashCheck: false,
};
this.oauthService.configure(authConfig);
this.oauthService.tokenValidationHandler = new JwksValidationHandler();
this.oauthService.loadDiscoveryDocumentAndTryLogin();
}
subscribeToOAuthEvents() {
this.oauthService.events.subscribe(e => {
if (e.type === 'token_received' || e.type === 'token_refreshed' ) {
this.storeTokenInDataService();
const self = this;
// this will wait for 2 hours minus 30 sec before it refreshes the access token;
setTimeout(() => { self.refreshToken(self); }, 7_170_000);
} else if (e.type === 'token_expires') {
this.logger.log('token_expires, going to refresh');
this.refreshToken(this);
} else if (e instanceof OAuthErrorEvent) {
this.logger.error('OAuth error:', e);
} else {
this.logger.log('OAuthEvent:', e);
}
});
}
storeTokenInDataService() {
this.token.access_token = this.oauthService.getAccessToken();
this.token.refresh_token = this.oauthService.getRefreshToken();
this.dataService.nextToken(this.token);
}
在我的主页中,我订阅了 sharedToken 但我不确定在发出令牌之前是否总是发生这种情况:
ngOnInit(): void {
console.log('going to get the token from dataService');
this.dataService.sharedToken
.pipe(
takeUntil(this.destroy$),
tap(token => {
this.token = token;
console.log('got Token');
}),
switchMap(token => {
this.headers = this.createHeaders(token.access_token);
return this.adapterService.getUserInfo(this.headers);
}))
.subscribe(UserInfo => {
this.logger.log('received userInfo : ', userInfo);
...
});
}
}
在我的 DataService 中,它看起来像这样:
private token = new Subject<Token>();
sharedPToken = this.token ;
nextToken(token: Token) {
this.token.next(token);
}
更新:问题已解决,我的最终主要组件如下所示:
ngOnInit(): void {
this.dataService.sharedTokenReplaySubject
.pipe(
takeLast(1),
tap(token => {
this.token = token;
console.log('got Token');
}),
switchMap(token => {
this.headers = this.createHeaders(token.access_token);
return this.adapterService.getUserInfo(this.headers);
}))
.subscribe(UserInfo => {
this.logger.log('received userInfo : ', userInfo);
...
});
}
}
解决方案
简而言之:你不能用Subject
.
您可以改用 RxJS ReplaySubject
。Subject
它是您使用的更通用的变体。然而,它可以“保持/缓冲”特定数量的先前发射,并在订阅后立即发射给未来的订阅者。在您的情况下,您可以使用缓冲区 1。它将保存并发出推送给它的最后一个推送值。
private token = new ReplaySubject<Token>(1); // <-- buffer 1
sharedToken = this.token.asObservable();
nextToken(token: Token) {
this.token.next(token);
}
这样,您无需担心该值是推送到token
订阅之前还是之后sharedToken
。即使值在订阅之前被推送到,订阅this.dataService.sharedToken
也会获得令牌token
。
推荐阅读
- java - 是否可以使用“密封方法”来改进密封类?
- sql - 在 Oracle 中获取结果的差异
- java - 多个下拉菜单
- reactjs - react-datepicker 与 react-final-form
- c# - 如何对数据表c#,linq中的列进行排序和求和?
- wordpress - 如何通过动态 WORDPRESS 设置发布顺序
- angular - 具有 ENUM 值的 StepLineSeries
- java - 对象框 build.gradle
- java - 如何在方括号之间拆分字符串,如下所示
- powershell - 如何使用 PowerShell 在当前目录中打开 Visual Studio 解决方案