Ionic/Angular应用关闭后自动登出,如何实现仅手动点击登出才退出
问题根因与解决方案
现有代码核心问题
- 登录状态判断存在异步时序问题:
Storage.get是异步操作,应用启动时路由守卫AuthGuard的canActivate同步取authenticationState初始值false,此时checkToken还未执行完成,导致已登录用户被误判为未登录 checkToken方法未覆盖member为空的场景,没有对未登录状态做赋值处理- 跳转逻辑散落在
AuthenticationService和app.component.ts两个位置,容易出现逻辑冲突 - 登录态存储逻辑不一致:
login方法存储了TOKEN_KEY但校验时未使用,logout方法仅删除member未同步清理TOKEN_KEY
代码修改步骤
1. 调整AuthenticationService逻辑
修改状态初始值,补全checkToken空值处理,移除service内的跳转逻辑:
// 调整初始状态为null,标识未完成校验 authenticationState = new BehaviorSubject<boolean | null>(null); async checkToken() { const memberRes = await this.storage.get("member"); if (memberRes) { const member = JSON.parse(memberRes); const token = member?.secret; if (token) { // 恢复内存中的用户信息 this.dataService.setData("member", member); this.observable.user.next(member.user); this.authenticationState.next(true); return; } } // 所有未满足登录条件的场景统一赋值为false this.authenticationState.next(false); } // 清理冗余的TOKEN_KEY存储,或者统一使用TOKEN_KEY做校验,这里以清理冗余为例 login(data) { return this.dataService.setStorageData("member", data).then(() => { this.dataService.setData("member", data); console.log("Member data", data); this.observable.user.next(data.user); this.authenticationState.next(true); return true; }); } // 登出同步清理所有存储的登录信息 logout() { return this.storage.remove("member").then(() => { this.badge.clear(); this.authenticationState.next(false); }); }
2. 重写AuthGuard适配异步校验
路由守卫返回Observable等待登录状态校验完成,避免时序问题:
import { Injectable } from "@angular/core"; import { CanActivate, Router } from "@angular/router"; import { AuthenticationService } from "../services/authentication/authentication.service"; import { NavController } from "@ionic/angular"; import { Observable } from "rxjs"; import { filter, take, tap } from "rxjs/operators"; @Injectable({ providedIn: "root", }) export class AuthGuard implements CanActivate { constructor( public auth: AuthenticationService, public router: Router, private navCtrl: NavController ) {} canActivate(): Observable<boolean> { return this.auth.authenticationState.pipe( // 等待登录状态校验完成,过滤掉初始null值 filter(state => state !== null), take(1), // 未登录跳转到登录页 tap(isAuthenticated => { if (!isAuthenticated) { this.navCtrl.navigateRoot(""); } }) ); } }
3. 统一app.component.ts的跳转逻辑
监听登录状态变化统一处理路由跳转,移除service内的跳转逻辑避免冲突:
// app.component.ts constructor内添加监听逻辑 constructor(private authService: AuthenticationService, private navCtrl: NavController) { this.authService.authenticationState.subscribe(isAuthenticated => { // 跳过未完成校验的状态 if (isAuthenticated === null) return; if (isAuthenticated) { this.navCtrl.navigateRoot("/tabs/tabs/home"); } else { this.navCtrl.navigateRoot(""); } }) }
内容的提问来源于stack exchange,提问作者Orick
相关产品推荐
相关产品推荐

