Angular认证守卫异步问题:登录后用户值未设置导致跳转失败
问题原因及解决方案
问题现象
访问首页被Auth Guard重定向到登录页;首次点击登录后,页面跳转至返回URL,但Auth Guard再次触发时user值仍未设置,导致停留在登录页;第二次点击登录才能正常跳转。
核心原因
你的auth.service.ts中,login方法里的map操作符搭配了async函数,这会让RxJS流的类型变成Observable<Promise<User>>,而非预期的Observable<User>。
当login.component.ts订阅这个流时,next回调会在内部Promise(也就是await this.getUserPermissions(user))还没执行完就触发,此时this.userSubject.next(user)根本没运行,userValue还是null。这时候跳转返回URL,Auth Guard检查userValue自然失败,会重定向回登录页。等到第二次点击登录时,之前的Promise可能已经完成,userSubject已有值,所以能正常跳转。
修复方案
把map换成switchMap,switchMap可以自动处理返回Promise的场景,会等待Promise解析完成后再发射值:
修改后的auth.service.ts
private userSubject: BehaviorSubject<User | null>; public get userValue() { return this.userSubject.value; } login(username: string, password: string) { return this.http.post<any>(`${environment().apiUrl}/auth/login`, { username, password }, { withCredentials: true }) .pipe(switchMap(async (user) => { user.permissions = await this.getUserPermissions(user); this.userSubject.next(user); this.startRefreshTokenTimer(); return user; })); }
为什么用switchMap而不是map?
map会直接把async函数返回的Promise作为流的下一个值发射,订阅时拿到的是Promise,不是解析后的user对象。switchMap会自动等待Promise解析完成,把解析后的值作为流的下一个值发射,这样订阅时的next回调会在userSubject.next(user)执行完后才触发,此时userValue已经有值,跳转返回URL时Auth Guard就能通过检查。
内容的提问来源于stack exchange,提问作者sirzento
相关产品推荐
相关产品推荐

