From cad74d7fdb2fdff1e8d23e81baf7c4bccb143126 Mon Sep 17 00:00:00 2001 From: wsczx Date: Thu, 31 Oct 2024 10:04:35 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=B2=E7=88=86=E5=A2=9E=E5=8A=A0=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=89=8B=E5=8A=A8=E8=A7=A3=E9=94=81=E7=9A=84=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/admin/lockmanager.go | 35 +++++++-- server/admin/server.go | 1 + web/src/layout/LayoutAside.vue | 15 ++-- web/src/pages/user/LockManager.vue | 109 +++++++++++++++++++++++++++++ web/src/plugins/router.js | 29 ++++---- 5 files changed, 157 insertions(+), 32 deletions(-) create mode 100644 web/src/pages/user/LockManager.vue diff --git a/server/admin/lockmanager.go b/server/admin/lockmanager.go index c7c99a3..cf6e523 100644 --- a/server/admin/lockmanager.go +++ b/server/admin/lockmanager.go @@ -97,7 +97,25 @@ func UnlockUser(w http.ResponseWriter, r *http.Request) { lm.mu.Lock() defer lm.mu.Unlock() - lm.Unlock(lockinfo.State) + // 根据用户名和IP查找锁定状态 + var state *LockState + switch { + case lockinfo.IP == "" && lockinfo.Username != "": + state = lm.userLocks[lockinfo.Username] // 全局用户锁定 + case lockinfo.Username != "" && lockinfo.IP != "": + if userIPMap, exists := lm.ipUserLocks[lockinfo.Username]; exists { + state = userIPMap[lockinfo.IP] // 单用户 IP 锁定 + } + default: + state = lm.ipLocks[lockinfo.IP] // 全局 IP 锁定 + } + + if state == nil || !state.Locked { + RespError(w, RespInternalErr, fmt.Errorf("锁定状态未找到或已解锁")) + return + } + + lm.Unlock(state) base.Info("解锁成功:", lockinfo.Description, lockinfo.Username, lockinfo.IP) RespSucess(w, "解锁成功!") @@ -112,7 +130,7 @@ func (lm *LockManager) GetLocksInfo() []LockInfo { for ip, state := range lm.ipLocks { if state.Locked { info := LockInfo{ - Description: "全局 IP 锁定", + Description: "全局IP锁定", Username: "", IP: ip, State: &LockState{ @@ -147,7 +165,7 @@ func (lm *LockManager) GetLocksInfo() []LockInfo { for ip, state := range ipStates { if state.Locked { info := LockInfo{ - Description: "单用户 IP 锁定", + Description: "单用户IP锁定", Username: username, IP: ip, State: &LockState{ @@ -205,7 +223,7 @@ func (lm *LockManager) IsWhitelisted(ip string) bool { } func (lm *LockManager) StartCleanupTicker() { - lm.cleanupTicker = time.NewTicker(5 * time.Minute) + lm.cleanupTicker = time.NewTicker(1 * time.Minute) go func() { for range lm.cleanupTicker.C { lm.CleanupExpiredLocks() @@ -220,20 +238,23 @@ func (lm *LockManager) CleanupExpiredLocks() { defer lm.mu.Unlock() for ip, state := range lm.ipLocks { - if now.Sub(state.LastAttempt) > time.Duration(base.Cfg.GlobalLockStateExpirationTime)*time.Second { + if !lm.CheckLockState(state, now, base.Cfg.GlobalIPLockTime) || + now.Sub(state.LastAttempt) > time.Duration(base.Cfg.GlobalLockStateExpirationTime)*time.Second { delete(lm.ipLocks, ip) } } for user, state := range lm.userLocks { - if now.Sub(state.LastAttempt) > time.Duration(base.Cfg.GlobalLockStateExpirationTime)*time.Second { + if !lm.CheckLockState(state, now, base.Cfg.GlobalUserLockTime) || + now.Sub(state.LastAttempt) > time.Duration(base.Cfg.GlobalLockStateExpirationTime)*time.Second { delete(lm.userLocks, user) } } for user, ipMap := range lm.ipUserLocks { for ip, state := range ipMap { - if now.Sub(state.LastAttempt) > time.Duration(base.Cfg.GlobalLockStateExpirationTime)*time.Second { + if !lm.CheckLockState(state, now, base.Cfg.LockTime) || + now.Sub(state.LastAttempt) > time.Duration(base.Cfg.GlobalLockStateExpirationTime)*time.Second { delete(ipMap, ip) if len(ipMap) == 0 { delete(lm.ipUserLocks, user) diff --git a/server/admin/server.go b/server/admin/server.go index 7329f87..dae1a66 100644 --- a/server/admin/server.go +++ b/server/admin/server.go @@ -88,6 +88,7 @@ func StartAdmin() { r.HandleFunc("/statsinfo/list", StatsInfoList) r.HandleFunc("/locksinfo/list", GetLocksInfo) + r.HandleFunc("/locksinfo/unlok", UnlockUser) // pprof if base.Cfg.Pprof { diff --git a/web/src/layout/LayoutAside.vue b/web/src/layout/LayoutAside.vue index cfbbc59..6bb927e 100644 --- a/web/src/layout/LayoutAside.vue +++ b/web/src/layout/LayoutAside.vue @@ -7,17 +7,9 @@ - + 首页 @@ -44,6 +36,7 @@ 用户列表 用户策略 在线用户 + 锁定管理 IP映射 diff --git a/web/src/pages/user/LockManager.vue b/web/src/pages/user/LockManager.vue new file mode 100644 index 0000000..c4986a8 --- /dev/null +++ b/web/src/pages/user/LockManager.vue @@ -0,0 +1,109 @@ + + + + + \ No newline at end of file diff --git a/web/src/plugins/router.js b/web/src/plugins/router.js index 07b42e5..1daff4d 100644 --- a/web/src/plugins/router.js +++ b/web/src/plugins/router.js @@ -1,35 +1,36 @@ import Vue from "vue"; import VueRouter from "vue-router"; -import {getToken} from "./token"; +import { getToken } from "./token"; Vue.use(VueRouter) const routes = [ - {path: '/login', component: () => import('@/pages/Login')}, + { path: '/login', component: () => import('@/pages/Login') }, { path: '/admin', component: () => import('@/layout/Layout'), redirect: '/admin/home', children: [ - {path: 'home', component: () => import('@/pages/Home')}, + { path: 'home', component: () => import('@/pages/Home') }, - {path: 'set/system', component: () => import('@/pages/set/System')}, - {path: 'set/soft', component: () => import('@/pages/set/Soft')}, - {path: 'set/other', component: () => import('@/pages/set/Other')}, - {path: 'set/audit', component: () => import('@/pages/set/Audit')}, + { path: 'set/system', component: () => import('@/pages/set/System') }, + { path: 'set/soft', component: () => import('@/pages/set/Soft') }, + { path: 'set/other', component: () => import('@/pages/set/Other') }, + { path: 'set/audit', component: () => import('@/pages/set/Audit') }, - {path: 'user/list', component: () => import('@/pages/user/List')}, - {path: 'user/policy', component: () => import('@/pages/user/Policy')}, - {path: 'user/online', component: () => import('@/pages/user/Online')}, - {path: 'user/ip_map', component: () => import('@/pages/user/IpMap')}, + { path: 'user/list', component: () => import('@/pages/user/List') }, + { path: 'user/policy', component: () => import('@/pages/user/Policy') }, + { path: 'user/online', component: () => import('@/pages/user/Online') }, + { path: 'user/ip_map', component: () => import('@/pages/user/IpMap') }, + { path: 'user/lockmanager', component: () => import('@/pages/user/LockManager') }, - {path: 'group/list', component: () => import('@/pages/group/List')}, + { path: 'group/list', component: () => import('@/pages/group/List') }, ], }, - {path: '*', redirect: '/admin/home'}, + { path: '*', redirect: '/admin/home' }, ] // 3. 创建 router 实例,然后传 `routes` 配置 @@ -64,7 +65,7 @@ router.beforeEach((to, from, next) => { } if (to.path === "/login") { - next({path: '/admin/home'}); + next({ path: '/admin/home' }); return; }