Angular 10 使用路由守卫时如何避免登录信息丢失?
权限拦截后登录态丢失问题
- 已开发两套路由守卫,分别匹配普通用户、管理员的页面访问权限校验规则
- 登录流程完成后,会将完整的用户信息存入自定义服务做内存缓存
- 当前异常表现:普通用户完成登录后,尝试访问仅管理员可进入的页面时,守卫可以正常执行拦截跳转,但自定义服务中存储的所有登录信息会被清空,导致用户被强制要求重新登录,需要找到规避该异常的方案
普通用户守卫实现代码
canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { if (this.loginAuthenthicationService.isAuthenticated) { return true; } this.router.navigate(['']); return false; }
管理员守卫实现代码
canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { if (this.loginAuthenthicationService.isAuthenticated && this.loggedUserService.loginCredentials.admin) { return true; } this.router.navigate(['']); return false; }
路由配置与守卫使用方式代码
{ path: 'profile', loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule), data: { preload: false, privilege: 'dashboard' }, canActivate: [AuthenticationGuard] }, { path: 'users', loadChildren: () => import('./user/user.module').then(m => m.UserModule), data: { preload: false, privilege: 'dashboard' }, canActivate: [AdminAuthenticationGuard] }
存储用户临时数据的自定义服务代码
export class LoggedUserService { constructor() { } loginCredentials = { voornaam: "", achternaam: "", email: "", admin: false } }
问题根因与修复方案
- 核心问题出在服务的作用域配置:当前
LoggedUserService没有绑定到根注入器做全局单例。如果这个服务是在某个懒加载的业务模块的providers数组中声明的,每次路由跳转、模块加载/销毁时,Angular会重新生成服务实例,实例初始化时loginCredentials会被重置为类定义的初始空值,表现出来就是登录信息被清空。 - 第一优先级修复:给
LoggedUserService添加根作用域的注入元数据,保证整个应用运行周期内只有唯一的服务实例:
@Injectable({ providedIn: 'root' }) export class LoggedUserService { constructor() { } loginCredentials = { voornaam: "", achternaam: "", email: "", admin: false } }
- 代码冗余优化:守卫拦截未通过时,不推荐直接调用
this.router.navigate执行跳转,这种写法会触发额外的路由导航流程,容易在流程链路中触发服务的重新实例化。可以直接在守卫方法中返回目标地址的UrlTree对象,让路由系统内部处理跳转,减少多余的流程开销:
canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree { if (this.loginAuthenthicationService.isAuthenticated && this.loggedUserService.loginCredentials.admin) { return true; } // 直接返回跳转目标,替代this.router.navigate(['']) return this.router.createUrlTree(['']); }
- 稳定性增强:仅依赖内存中的服务实例存储登录态是不可靠的,一旦发生页面刷新、应用异常重启,服务实例会被重新初始化,所有缓存的登录信息都会丢失。建议将必要的登录信息同步存入浏览器本地存储,在服务初始化时从本地存储读取数据回填,避免实例重建导致的登录态丢失。
内容的提问来源于stack exchange,提问作者Tyednut
相关产品推荐
相关产品推荐

