Angular 6-如何在服务中使用可观察对象来等待Okta令牌存在于localstorage中
在我的应用程序中,我使用第三方身份验证登录用户,然后在其本地存储中设置令牌。我正在编写一个缓存配置文件信息的服务,它使用该用户的身份验证令牌并调用Angular 6-如何在服务中使用可观察对象来等待Okta令牌存在于localstorage中,angular,typescript,rxjs,Angular,Typescript,Rxjs,在我的应用程序中,我使用第三方身份验证登录用户,然后在其本地存储中设置令牌。我正在编写一个缓存配置文件信息的服务,它使用该用户的身份验证令牌并调用getUser()后端方法来返回用户配置文件信息 this._authService.isLoggedIn().pipe( concatMap(() => { const username = this._authService.getUser(); return this._adService.get
getUser()
后端方法来返回用户配置文件信息
this._authService.isLoggedIn().pipe(
concatMap(() => {
const username = this._authService.getUser();
return this._adService.getUser(username)
}),
map(res => res[0])
).subscribe(profile => {
this.userProfileSubject.next(profile);
});
}
问题在于,在localstorage中设置令牌与应用程序依赖令牌在初始化时进行后端调用之间存在轻微延迟
export class UserService {
private userProfileSubject = new BehaviorSubject<Enduser>(new Enduser());
userProfile$ = this.userProfileSubject.asObservable();
constructor(
private _adService: AdService,
private _authService: AuthnService) { }
setUserProfile() {
const username = this._authService.getUser();
this.userProfile$ = this._adService.getUser(username).pipe(
first(),
map(result => result[0]),
publishReplay(1),
refCount()
);
return this.userProfile$;
}
}
所以this.\u authService.getUser()
需要先完成,然后才能在中使用它。\u adService.getUser(username)
我认为这样做的方法是让getUser()
方法返回一个可观察的takeWhile
,直到值为!==空
。或使用定时器
。我试了几个小时都没有成功
非常感谢您的帮助
__
编辑:
这似乎是可行的,但使用定时器
让我觉得非常不方便,我宁愿用另一种方式:
在user.service.ts
中:
setUserProfile() {
timer(100).pipe(
concatMap(() => {
const username = this._authService.getUser();
return this._adService.getUser(username)
}),
map(res => res[0])
).subscribe(profile => {
this.userProfileSubject.next(profile);
});
}
在app.component.ts
ngOnInit
this._userService.setUserProfile();
this._userService.userProfile$.pipe(
map((user: Enduser) => this._userService.setUserPermissions(user)),
takeUntil(this.ngUnsubscribe)
).subscribe();
编辑2:工作解决方案
isLoggedIn()
是设置本地存储的方法。在这里,我等待它被设置,然后继续获取用户配置文件信息
this._authService.isLoggedIn().pipe(
concatMap(() => {
const username = this._authService.getUser();
return this._adService.getUser(username)
}),
map(res => res[0])
).subscribe(profile => {
this.userProfileSubject.next(profile);
});
}
伊斯洛格丁:
isLoggedIn(state): Observable<boolean> {
...
return this.http.get(url, {withCredentials: true}).pipe(
map((res: any) => {
const token = res.mdoc.token;
if (token) {
localStorage.setItem(environment.JWT_TOKEN_NAME, token);
return true;
} else {
return false;
}
})
}
isLoggedIn(状态):可观察{
...
返回此.http.get(url,{withCredentials:true}).pipe(
映射((res:any)=>{
const token=res.mdoc.token;
如果(令牌){
setItem(environment.JWT_TOKEN_NAME,TOKEN);
返回true;
}否则{
返回false;
}
})
}
可能有一种方法可以移除嵌套管道。我无法对其进行测试,但这应该也可以,而且更干净一些:
const usernameObs = of(this._authService.getUser());
return usernameObs.pipe(
flatMap(username => {
return this._adService.getUser(username);
}),
first(),
map(result => result[0]),
publishReplay(1),
refCount()
)
如我在评论中所述,您希望等待
this.\u authService.getUser()
完成的问题没有意义,因为如果this.\u authService.getUser()
是同步的(如您所述),那么它将始终在执行下一行代码之前完成
不管怎样,在阅读了你的代码后,我想我知道你想做什么
this.\u authService.getUser()
this.\u adService.getUser()
this.\u adService.getUser()
完成并将其值传递给可观察流,userProfile$
export class UserService {
private userProfileSubject = new BehaviorSubject<Enduser>(new Enduser());
userProfile$ = this.userProfileSubject.asObservable();
constructor(
private _adService: AdService,
private _authService: AuthnService
) {}
setUserProfile() {
const username = this._authService.getUser();
this._adService.getUser(username).subscribe((userProfile: Enduser) => {
this.userProfileSubject.next(userProfile);
});
}
}
我的实施:
setUserProfile() {
this.userProfile$ = this._authService.isLoggedIn(this.activatedRoute.snapshot).pipe(
concatMap(() => {
return this._adService.getUser(this._authService.getUser()).pipe(
map(result => result[0]),
publishReplay(1),
refCount()
);
})
)
return this.userProfile$;
}
}
_____
// _adService.getUser()
getUser(username: string): Observable<Enduser> {
const usernameUrl = encodeURIComponent(username);
return this.http.get(`${environment.API_URL}person/${usernameUrl}`).pipe(
map((res: any) => res.data)
);
}
_____
// _authService.getUser()
public getUser(): string {
const jwtHelper = new JwtHelperService()
const token = localStorage.getItem(environment.JWT_TOKEN_NAME);
if (!token || jwtHelper.isTokenExpired(token)) {
return null;
} else {
const t = jwtHelper.decodeToken(token);
return t.username;
}
}
setUserProfile(){
this.userProfile$=this.\u authService.isLoggedIn(this.activatedRoute.snapshot).pipe(
concatMap(()=>{
返回此.\u adService.getUser(此.\u authService.getUser()).pipe(
映射(结果=>结果[0]),
出版重播(1),
refCount()
);
})
)
返回此.userProfile$;
}
}
_____
//_adService.getUser()
getUser(用户名:字符串):可观察{
const usernameUrl=encodeURIComponent(用户名);
返回此.http.get(`${environment.API_URL}person/${usernameUrl}`).pipe(
映射((res:any)=>res.data)
);
}
_____
//_authService.getUser()
public getUser():字符串{
const jwtHelper=newjwthelperservice()
const-token=localStorage.getItem(environment.JWT\u-token\u-NAME);
如果(!token | | jwtHelper.isTokenExpired(token)){
返回null;
}否则{
const t=jwtHelper.decodeToken(令牌);
返回t.username;
}
}
这没有意义…如果这是同步的。\u authService.getUser()
是同步的,那么“需要完成才能使用它”是什么意思?它总是在执行下一行之前完成,因为它是同步的。老兄,老实说,你让你的代码变得比需要的更复杂、更不可读。你怎么知道每次100毫秒后Okta都会完成?在现实世界中,你会遇到延迟等问题……这不是一个好的解决方案。保持简单……只是不要这样调用setUserProfile
直到Okta完成,而不是执行所有这些不必要的黑客计时器逻辑。阅读我最近对我的答案的评论。是的,你是对的:它不能是同步的,否则我就不会有这个问题。上面的问题是this.\u authService.getUser();
第一次返回为null
(这是我所有尝试的问题)。你怎么看?转到开发人员工具并手动查看本地存储。问自己几个问题:1.令牌是否确实存在于本地存储中?2.如果存在,它是否过期?如果没有过期,你的代码逻辑可能不正确。如果过期,那就是你的问题。你的代码在过期时返回null。但这不应该是错误的本地存储API是同步的还是异步的问题。如果我在console.log(token)
之后放置const token=localStorage.getItem(environment.JWT\u token\u NAME);
在getUser()中
,令牌的初始值为空。我们正在使用Okta进行身份验证,令牌正在设置中,但在加载应用程序后稍有变化。我在setUserProfile()中设置了一个超时(100)
-此时令牌已显示。我已使用上面最新的更新。好的,所以问题不是本地存储,而是数据在几毫秒后才存储在那里。我将尝试找出如何将setUserProfile
逻辑的执行延迟到Okta设置令牌之后,不管我显示的逻辑如何在我的示例中,ed应该可以正常工作。再一次,确保在Okta设置令牌之前不会调用setUserProfile
。他们有什么API可以挂接,比如
constructor(private _userService: UserService) {
_userService.userProfile$.subscribe((userProfile: Enduser) => {
console.log(userProfile);
});
}
setUserProfile() {
this.userProfile$ = this._authService.isLoggedIn(this.activatedRoute.snapshot).pipe(
concatMap(() => {
return this._adService.getUser(this._authService.getUser()).pipe(
map(result => result[0]),
publishReplay(1),
refCount()
);
})
)
return this.userProfile$;
}
}
_____
// _adService.getUser()
getUser(username: string): Observable<Enduser> {
const usernameUrl = encodeURIComponent(username);
return this.http.get(`${environment.API_URL}person/${usernameUrl}`).pipe(
map((res: any) => res.data)
);
}
_____
// _authService.getUser()
public getUser(): string {
const jwtHelper = new JwtHelperService()
const token = localStorage.getItem(environment.JWT_TOKEN_NAME);
if (!token || jwtHelper.isTokenExpired(token)) {
return null;
} else {
const t = jwtHelper.decodeToken(token);
return t.username;
}
}