From f6a1fb62886c7bc05346d234e3576462b4c96abf Mon Sep 17 00:00:00 2001 From: kevin Date: Fri, 10 Jul 2026 13:33:04 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=B8=A2=E4=B8=8B=E7=BA=BF=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E7=A6=81=E7=94=A8=E8=B4=A6=E5=8F=B7=E9=98=B2=E9=87=8D?= =?UTF-8?q?=E8=BF=9E=EF=BC=8C=E7=A6=81=E6=AD=A2=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E8=B8=A2=E8=87=AA=E5=B7=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - handler/vpn.go: KickUserClient 踢线后设置 status=0 并失效所有会话, 阻止客户端自动重连;新增自检,目标为当前管理员时返回 400 - AdminView.vue: handleKick 调用 API 前自检,自己则提示去修改密码 - zh.ts/en.ts: 新增 cannotKickSelf,更新 confirmKick 提示含禁用账号 --- frontend/src/locales/en.ts | 3 ++- frontend/src/locales/zh.ts | 3 ++- frontend/src/views/AdminView.vue | 6 +++++- internal/handler/vpn.go | 16 ++++++++++++---- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/frontend/src/locales/en.ts b/frontend/src/locales/en.ts index d6ccafb..c077f45 100644 --- a/frontend/src/locales/en.ts +++ b/frontend/src/locales/en.ts @@ -150,8 +150,9 @@ export default { selectUserAndIp: 'Please select a user and fill in at least one IP address', confirmDeleteReservation: 'Delete this reservation?', kick: 'Kick', - confirmKick: 'Disconnect all VPN connections for user {username}?', + confirmKick: 'Disconnect all VPN connections for user {username} and disable their account?', kickFailed: 'Failed to kick user', + cannotKickSelf: 'Cannot kick yourself. To disconnect your own devices, please change your password.', }, footer: { lastCommit: 'Last commit', diff --git a/frontend/src/locales/zh.ts b/frontend/src/locales/zh.ts index 1a3c808..dec89d1 100644 --- a/frontend/src/locales/zh.ts +++ b/frontend/src/locales/zh.ts @@ -149,8 +149,9 @@ export default { selectUserAndIp: '请选择用户并至少填写一个 IP 地址', confirmDeleteReservation: '确认删除该预留?', kick: '踢下线', - confirmKick: '确定要断开用户 {username} 的所有 VPN 连接吗?', + confirmKick: '确定要断开用户 {username} 的所有 VPN 连接并禁用其账号吗?', kickFailed: '踢下线失败', + cannotKickSelf: '不能踢自己下线,如需断开自己的设备请修改密码', }, footer: { lastCommit: '最后提交', diff --git a/frontend/src/views/AdminView.vue b/frontend/src/views/AdminView.vue index c930316..66e9929 100644 --- a/frontend/src/views/AdminView.vue +++ b/frontend/src/views/AdminView.vue @@ -83,8 +83,12 @@ async function fetchVpnStatus() { } async function handleKick(userId: number, username: string) { - if (!confirm(t('vpn.confirmKick', { username }))) return kickError.value = '' + if (userId === authStore.user?.id) { + kickError.value = t('vpn.cannotKickSelf') + return + } + if (!confirm(t('vpn.confirmKick', { username }))) return try { const res = await fetch(`/api/admin/vpn/clients/${userId}`, { method: 'DELETE', diff --git a/internal/handler/vpn.go b/internal/handler/vpn.go index 148bd92..10af5db 100644 --- a/internal/handler/vpn.go +++ b/internal/handler/vpn.go @@ -421,11 +421,19 @@ func KickUserClient(c *gin.Context) { return } - if vpn.VPN == nil || !vpn.VPN.Running() { - c.JSON(http.StatusOK, gin.H{"message": "VPN 服务未运行", "kicked": 0}) + currentUserID, _ := c.Get("user_id") + if uint(id) == currentUserID.(uint) { + c.JSON(http.StatusBadRequest, gin.H{"error": "不能踢自己下线,如需断开自己的设备请修改密码"}) return } - n := vpn.VPN.KickUser(uint(id)) - c.JSON(http.StatusOK, gin.H{"message": "已断开用户连接", "kicked": n}) + n := 0 + if vpn.VPN != nil && vpn.VPN.Running() { + n = vpn.VPN.KickUser(uint(id)) + } + + db.DB.Model(&user).Update("status", 0) + db.DB.Model(&model.Session{}).Where("user_id = ?", id).Update("invalid", true) + + c.JSON(http.StatusOK, gin.H{"message": "已断开用户连接并禁用账号", "kicked": n}) }