如何在Angular 2/5项目中为本地存储设置类.Net会话超时?
在Angular 2/5中实现类似.Net的会话超时功能
我之前在Angular项目里做过类似的会话超时需求,结合本地存储和session变量的话,可以按下面这几步来操作,亲测好用:
1. 登录时记录会话关键信息
登录成功后,把登录时间、超时时长(比如30分钟)以及用户的session数据存在本地存储里,这样页面刷新后也能恢复会话状态:
// 登录成功后的处理逻辑 login(userCredentials: any) { // 调用登录接口获取session信息 this.authService.login(userCredentials).subscribe((response) => { // 保存session数据到sessionStorage(比localStorage更安全,关闭浏览器自动清除) sessionStorage.setItem('userSession', JSON.stringify(response.session)); // 记录登录时间戳(毫秒) sessionStorage.setItem('loginTimestamp', new Date().getTime().toString()); // 设置超时时长,比如30分钟=1800000毫秒 sessionStorage.setItem('sessionTimeout', '1800000'); // 初始化超时计时器 this.sessionTimeoutService.initTimeout(); }); }
2. 封装会话超时服务
创建一个SessionTimeoutService来统一管理超时逻辑,里面包含监听用户活动、重置计时器、触发超时登出的功能:
import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class SessionTimeoutService { private timeoutTimer: any; private timeoutDuration: number; // 用于通知其他组件会话已过期 public sessionExpired$ = new Subject<void>(); constructor(private router: Router) {} initTimeout() { // 从存储中获取超时时长 this.timeoutDuration = parseInt(sessionStorage.getItem('sessionTimeout') || '1800000', 10); // 清除之前的计时器(避免重复触发) this.clearAllTimers(); // 设置新的超时计时器 this.setTimeout(); // 监听用户活动,有操作就重置计时 this.listenToUserActions(); } private setTimeout() { this.timeoutTimer = setTimeout(() => { // 超时后执行登出逻辑 this.handleSessionExpiry(); }, this.timeoutDuration); } private clearAllTimers() { if (this.timeoutTimer) { clearTimeout(this.timeoutTimer); } } private listenToUserActions() { // 监听用户常见操作:鼠标移动、键盘输入、点击、滚动 const activityEvents = ['mousemove', 'keydown', 'click', 'scroll']; activityEvents.forEach(event => { window.addEventListener(event, () => this.resetTimeout()); }); } private resetTimeout() { // 用户有操作就重置计时器 this.clearAllTimers(); this.setTimeout(); // 更新登录时间戳,让超时计算更精准 sessionStorage.setItem('loginTimestamp', new Date().getTime().toString()); } private handleSessionExpiry() { // 清除存储中的会话数据 sessionStorage.removeItem('userSession'); sessionStorage.removeItem('loginTimestamp'); sessionStorage.removeItem('sessionTimeout'); // 通知所有订阅组件会话过期 this.sessionExpired$.next(); // 跳转到登录页 this.router.navigate(['/login']); } // 手动登出时调用,统一清除资源 logout() { this.handleSessionExpiry(); } }
3. 页面刷新后恢复超时逻辑
在根组件(比如AppComponent)的ngOnInit里检查是否存在有效会话,如果有的话重新初始化超时服务,避免页面刷新后超时逻辑失效:
import { Component, OnInit } from '@angular/core'; import { SessionTimeoutService } from './services/session-timeout.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { constructor(private sessionTimeoutService: SessionTimeoutService) {} ngOnInit() { // 检查是否有已登录的会话 const userSession = sessionStorage.getItem('userSession'); const loginTimestamp = sessionStorage.getItem('loginTimestamp'); if (userSession && loginTimestamp) { const currentTime = new Date().getTime(); const timeoutDuration = parseInt(sessionStorage.getItem('sessionTimeout') || '1800000', 10); // 计算剩余超时时间 const remainingTime = timeoutDuration - (currentTime - parseInt(loginTimestamp, 10)); if (remainingTime > 0) { // 重置计时器为剩余时间(可以在服务里扩展一个initWithRemainingTime方法优化) this.sessionTimeoutService.initTimeout(); } else { // 剩余时间不足,直接触发登出 this.sessionTimeoutService.handleSessionExpiry(); } } } }
4. 可选:超时前弹窗提醒用户
如果需要像很多系统那样,在超时前几分钟弹出提示,询问用户是否要继续会话,可以在服务里加个预提醒逻辑:
// 在SessionTimeoutService里添加以下代码 private warningTimer: any; private warningDuration = 300000; // 提前5分钟提醒 setTimeout() { // 先设置超时提醒 this.warningTimer = setTimeout(() => { if (confirm('您的会话即将过期,是否继续保持登录?')) { this.resetTimeout(); } else { this.handleSessionExpiry(); } }, this.timeoutDuration - this.warningDuration); // 再设置最终超时计时器 this.timeoutTimer = setTimeout(() => { this.handleSessionExpiry(); }, this.timeoutDuration); } private clearAllTimers() { if (this.timeoutTimer) clearTimeout(this.timeoutTimer); if (this.warningTimer) clearTimeout(this.warningTimer); }
注意事项
- 敏感的session数据建议用
sessionStorage存储,它会在浏览器关闭后自动清除,比localStorage更安全; - 如果项目里有HTTP拦截器,记得在会话过期后拦截后续API请求,避免无效请求发送到后端;
- 在用户手动登出时,一定要调用服务的
logout方法,确保所有计时器和存储数据都被清除。
内容的提问来源于stack exchange,提问作者Arturo Laos
相关产品推荐
相关产品推荐

