如何阻止Angular路由守卫在无用户操作时自动跳转
解决Angular应用闲置10分钟自动跳转首页问题
问题根源
应用自动跳转的核心原因是Token过期后路由守卫验证失败:当前TokenService的isValid()方法仅验证了token的签发者(iss),没有检查token的过期时间(exp)。当token在10分钟后过期,loggedIn()返回false,AfterLoginService守卫会阻止访问受保护路由,触发路由默认跳转行为(回到首页)。
解决方案
1. 完善Token的过期时间验证
修改token.service.ts,在isValid()方法中加入token过期时间检查:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class TokenService { private iss = { login: 'https://Backend/api/login.php', signup: 'https://Backend/api/signup.php', } constructor() { } handle(token) { this.set(token); } set(token) { localStorage.setItem('token', token); } get() { return localStorage.getItem('token'); } remove() { localStorage.removeItem('token'); } isValid() { const token = this.get(); if (!token || token === 'undefined') { return false; } const payload = this.payload(token); if (!payload) { return false; } // 新增:检查token是否过期 const currentTime = Math.floor(Date.now() / 1000); if (payload.exp <= currentTime) { this.remove(); // 过期后清除无效token return false; } // 验证签发者 return Object.values(this.iss).includes(payload.iss); } payload(token) { try { const payload = token.split('.')[1]; return this.decode(payload); } catch (e) { return null; // 处理无效token的异常 } } decode(payload) { return JSON.parse(atob(payload)); } loggedIn() { return this.isValid(); } }
2. 优化路由守卫的跳转逻辑
当前守卫仅返回布尔值,Angular会默认跳转至路由配置的初始页。修改AfterLoginService,在验证失败时主动跳转登录页,并保存当前路由地址,方便用户登录后回到原页面:
import { Injectable } from "@angular/core"; import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { Observable } from 'rxjs'; import { TokenService } from './token.service'; @Injectable() export class AfterLoginService implements CanActivate { constructor(private Token: TokenService, private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> | Promise<boolean> { if (this.Token.loggedIn()) { return true; } // 保存当前路由,登录后跳转回来 localStorage.setItem('redirectUrl', state.url); // 主动跳转登录页 this.router.navigate(['/login']); return false; } }
3. 可选:添加用户活动监听(延长会话)
如果希望避免用户闲置时token过期,可以监听用户的鼠标、键盘等操作,重置过期计时器,或者调用后端接口刷新token:
// 新建IdleService import { Injectable, OnDestroy } from '@angular/core'; import { TokenService } from './token.service'; import { Router } from '@angular/router'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class IdleService implements OnDestroy { private destroy$ = new Subject<void>(); private idleTimer: any; private readonly IDLE_TIMEOUT = 10 * 60 * 1000; // 10分钟 constructor(private tokenService: TokenService, private router: Router) { this.initIdleListener(); } private initIdleListener() { // 监听用户活动 ['mousemove', 'keydown', 'click', 'scroll'].forEach(event => { window.addEventListener(event, () => this.resetIdleTimer()); }); this.resetIdleTimer(); } private resetIdleTimer() { clearTimeout(this.idleTimer); this.idleTimer = setTimeout(() => { // 闲置超时后的处理:可以提醒用户,或自动刷新token if (this.tokenService.loggedIn()) { // 示例:调用后端刷新token,若刷新失败再跳转登录 // this.authService.refreshToken().pipe(takeUntil(this.destroy$)).subscribe({ // next: () => this.resetIdleTimer(), // error: () => { // this.tokenService.remove(); // this.router.navigate(['/login']); // } // }); } }, this.IDLE_TIMEOUT); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); clearTimeout(this.idleTimer); } }
在AppComponent中注入该服务以启用监听:
import { Component } from '@angular/core'; import { IdleService } from './idle.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent { constructor(private idleService: IdleService) {} }
总结
- 核心是完善token的过期验证,确保守卫能准确判断用户登录状态
- 优化守卫的跳转逻辑,提升用户体验
- 可选的闲置监听可以避免用户无操作时被强制退出
内容的提问来源于stack exchange,提问作者SkullSrusher
相关产品推荐
相关产品推荐

