You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测用户活跃状态与浏览器状态?自动更新loggedIn字段方案

实现用户活跃状态检测与自动登出

完全可以实现这个需求,需要结合前端用户行为监听和后端定时任务兜底来完成,以下是具体方案:

1. 数据库模型修改

首先给User模型添加last_active字段,用于记录用户最后活跃时间,方便判断是否超时:

from datetime import datetime

class User(db.Model, UserMixin):
    id              =   db.Column(db.Integer, primary_key=True)
    user            =   db.Column(db.String(64), unique=True)
    userDetailed    =   db.Column(db.String(64))
    password        =   db.Column(db.String(64))
    loggedIn        =   db.Column(db.Boolean, default=False)
    last_active     =   db.Column(db.DateTime, default=datetime.utcnow)  # 新增:记录最后活跃时间

2. 前端监听逻辑

在用户登录后的页面(比如编辑器页面)添加JS代码,监听用户交互和窗口关闭事件,向后端发送状态信号:

// 初始化活跃计时器
let activityTimer;

// 重置计时器并发送心跳
function resetActivityTimer() {
    clearTimeout(activityTimer);
    // 5分钟无活动则触发心跳(可根据需求调整时长)
    activityTimer = setTimeout(sendHeartbeat, 300000);
    sendHeartbeat(); // 页面加载/用户操作时立即发送心跳
}

// 发送心跳请求通知后端用户活跃
function sendHeartbeat() {
    fetch('/heartbeat', {
        method: 'POST',
        credentials: 'include', // 携带登录会话Cookie
        headers: { 'Content-Type': 'application/json' }
    });
}

// 监听用户交互事件(鼠标移动、按键、滚动)
window.addEventListener('mousemove', resetActivityTimer);
window.addEventListener('keydown', resetActivityTimer);
window.addEventListener('scroll', resetActivityTimer);

// 监听窗口关闭/标签页切换,用sendBeacon保证请求能发出
window.addEventListener('beforeunload', () => {
    navigator.sendBeacon('/logout-on-close', JSON.stringify({}));
});

// 页面加载时启动监听
resetActivityTimer();

3. 后端接口实现

添加两个接口处理前端的心跳和关闭通知,同时添加定时任务兜底:

3.1 心跳接口

更新用户最后活跃时间:

from datetime import datetime
from flask import request, jsonify
from flask_login import login_required, current_user

@app.route('/heartbeat', methods=['POST'])
@login_required
def heartbeat():
    current_user.last_active = datetime.utcnow()
    db.session.commit()
    return jsonify({'status': 'success'}), 200

3.2 窗口关闭通知接口

收到通知后立即标记用户为未登录:

@app.route('/logout-on-close', methods=['POST'])
@login_required
def logout_on_close():
    current_user.loggedIn = False
    db.session.commit()
    return '', 204  # 返回无内容响应

3.3 定时兜底任务

处理浏览器崩溃、网络异常等前端无法发送通知的场景,定期检查超时用户:

from datetime import timedelta
from apscheduler.schedulers.background import BackgroundScheduler

def check_inactive_users():
    # 设置超时时间:15分钟无活跃则自动登出(可调整)
    timeout_threshold = datetime.utcnow() - timedelta(minutes=15)
    # 筛选出已登录且超时的用户
    inactive_users = User.query.filter(
        User.loggedIn == True,
        User.last_active < timeout_threshold
    ).all()
    # 更新状态
    for user in inactive_users:
        user.loggedIn = False
        db.session.commit()

# 初始化定时任务,每分钟检查一次
scheduler = BackgroundScheduler()
scheduler.add_job(check_inactive_users, 'interval', minutes=1)
scheduler.start()

# 应用关闭时停止定时任务
@app.teardown_appcontext
def shutdown_scheduler(exception=None):
    scheduler.shutdown()

4. 登录代码优化

用户登录成功时,同步更新last_active字段:

# 在登录逻辑的else分支中添加
user.loggedIn = True
user.last_active = datetime.utcnow()  # 新增:记录登录时的活跃时间
login_user(user)
db.session.commit()
return destination

注意事项

  • navigator.sendBeacon是异步请求,不会阻塞页面关闭,但极端情况(如浏览器强制崩溃)下可能无法触发,因此定时任务是必要的兜底机制。
  • 心跳频率和超时时间可根据业务需求调整,比如敏感系统可缩短超时时间(如5分钟)。
  • 生产环境中,APScheduler建议使用Redis等持久化存储作为任务调度器的后端,避免应用重启后任务丢失。
  • 确保Flask的会话配置正确,前端请求能携带登录Cookie,否则current_user无法正确获取用户信息。

内容的提问来源于stack exchange,提问作者Thore Blesse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 00:11:11