From eb8d55040ca02f9b9d68aa9fa165a4af54b556e5 Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Fri, 4 Nov 2022 15:15:58 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=B4=BB=E5=8A=A8=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/cron/clear_user_act_log.go | 20 ++ server/cron/start.go | 1 + server/dbdata/audit.go | 6 + server/dbdata/db.go | 2 +- server/dbdata/tables.go | 14 ++ server/dbdata/user_act_log.go | 170 +++++++++++++++ server/dbdata/user_act_log_test.go | 72 +++++++ server/handler/link_auth.go | 15 +- server/handler/link_cstp.go | 1 + server/handler/link_dtls.go | 1 + server/handler/link_tunnel.go | 8 + server/sessdata/session.go | 24 +++ web/src/components/audit/Access.vue | 321 ++++++++++++++++++++++++++++ web/src/components/audit/ActLog.vue | 256 ++++++++++++++++++++++ web/src/pages/set/Audit.vue | 317 ++++----------------------- 15 files changed, 947 insertions(+), 281 deletions(-) create mode 100644 server/cron/clear_user_act_log.go create mode 100644 server/dbdata/user_act_log.go create mode 100644 server/dbdata/user_act_log_test.go create mode 100644 web/src/components/audit/Access.vue create mode 100644 web/src/components/audit/ActLog.vue diff --git a/server/cron/clear_user_act_log.go b/server/cron/clear_user_act_log.go new file mode 100644 index 0000000..b407d8c --- /dev/null +++ b/server/cron/clear_user_act_log.go @@ -0,0 +1,20 @@ +package cron + +import ( + "github.com/bjdgyc/anylink/base" + "github.com/bjdgyc/anylink/dbdata" +) + +// 清除用户活动日志 +func ClearUserActLog() { + lifeDay, timesUp := isClearTime() + if !timesUp { + return + } + // 当审计日志永久保存时,则退出 + if lifeDay <= 0 { + return + } + affected, err := dbdata.UserActLogIns.ClearUserActLog(getTimeAgo(lifeDay)) + base.Info("Cron ClearUserActLog: ", affected, err) +} diff --git a/server/cron/start.go b/server/cron/start.go index 96159ab..c67405f 100644 --- a/server/cron/start.go +++ b/server/cron/start.go @@ -11,6 +11,7 @@ func Start() { s := gocron.NewScheduler(time.Local) s.Cron("0 * * * *").Do(ClearAudit) s.Cron("0 * * * *").Do(ClearStatsInfo) + s.Cron("0 * * * *").Do(ClearUserActLog) s.Every(1).Day().At("00:00").Do(sessdata.CloseUserLimittimeSession) s.StartAsync() } diff --git a/server/dbdata/audit.go b/server/dbdata/audit.go index d54f315..603b061 100644 --- a/server/dbdata/audit.go +++ b/server/dbdata/audit.go @@ -14,6 +14,7 @@ type SearchCon struct { AccessProto string `json:"access_proto"` Date []string `json:"date"` Info string `json:"info"` + Sort int `json:"sort"` } func GetAuditSession(search string) *xorm.Session { @@ -47,6 +48,11 @@ func GetAuditSession(search string) *xorm.Session { if searchData.Info != "" { session.And("info LIKE ?", "%"+searchData.Info+"%") } + if searchData.Sort == 1 { + session.OrderBy("id desc") + } else { + session.OrderBy("id asc") + } return session } diff --git a/server/dbdata/db.go b/server/dbdata/db.go index d65266b..aff9084 100644 --- a/server/dbdata/db.go +++ b/server/dbdata/db.go @@ -33,7 +33,7 @@ func initDb() { } // 初始化数据库 - err = xdb.Sync2(&User{}, &Setting{}, &Group{}, &IpMap{}, &AccessAudit{}, &Policy{}, &StatsNetwork{}, &StatsCpu{}, &StatsMem{}, &StatsOnline{}) + err = xdb.Sync2(&User{}, &Setting{}, &Group{}, &IpMap{}, &AccessAudit{}, &Policy{}, &StatsNetwork{}, &StatsCpu{}, &StatsMem{}, &StatsOnline{}, &UserActLog{}) if err != nil { base.Fatal(err) } diff --git a/server/dbdata/tables.go b/server/dbdata/tables.go index 53dff7a..fccb102 100644 --- a/server/dbdata/tables.go +++ b/server/dbdata/tables.go @@ -40,6 +40,20 @@ type User struct { UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"` } +type UserActLog struct { + Id int `json:"id" xorm:"pk autoincr not null"` + Username string `json:"username" xorm:"varchar(60)"` + GroupName string `json:"group_name" xorm:"varchar(60)"` + IpAddr string `json:"ip_addr" xorm:"varchar(32)"` + RemoteAddr string `json:"remote_addr" xorm:"varchar(32)"` + Os uint8 `json:"os" xorm:"not null default 0 Int"` + Client uint8 `json:"client" xorm:"not null default 0 Int"` + Version string `json:"version" xorm:"varchar(15)"` + Status uint8 `json:"status" xorm:"not null default 0 Int"` + Info string `json:"info" xorm:"varchar(255) not null default ''"` // 详情 + CreatedAt time.Time `json:"created_at" xorm:"DateTime created"` +} + type IpMap struct { Id int `json:"id" xorm:"pk autoincr not null"` IpAddr string `json:"ip_addr" xorm:"varchar(32) not null unique"` diff --git a/server/dbdata/user_act_log.go b/server/dbdata/user_act_log.go new file mode 100644 index 0000000..0f956c6 --- /dev/null +++ b/server/dbdata/user_act_log.go @@ -0,0 +1,170 @@ +package dbdata + +import ( + "net/url" + "regexp" + "strings" + + "github.com/ivpusic/grpool" + "github.com/spf13/cast" + "xorm.io/xorm" +) + +const ( + UserAuthFail = 0 // 认证失败 + UserAuthSuccess = 1 // 认证成功 + UserConnected = 2 // 连线成功 + UserLogout = 3 // 用户登出 +) + +type UserActLogProcess struct { + Pool *grpool.Pool + StatusOps []string + OsOps []string + ClientOps []string + InfoOps []string +} + +var ( + UserActLogIns = &UserActLogProcess{ + Pool: grpool.NewPool(1, 100), + StatusOps: []string{ // 操作类型 + UserAuthFail: "认证失败", + UserAuthSuccess: "认证成功", + UserConnected: "连接成功", + UserLogout: "用户登出", + }, + OsOps: []string{ // 操作系统 + 0: "Windows", + 1: "macOS", + 2: "Linux", + 3: "Android", + 4: "iOS", + }, + ClientOps: []string{ // 客户端 + 0: "AnyConnect", + 1: "OpenConnect", + 2: "unknown", + }, + InfoOps: []string{ // 信息 + 0: "用户掉线", + 1: "用户/客户端主动断开", + 2: "用户被踢下线(管理员/账号过期)", + }, + } +) + +// 异步写入用户操作日志 +func (ua *UserActLogProcess) Add(u UserActLog, userAgent string) { + os_idx, client_idx, ver := ua.ParseUserAgent(userAgent) + u.Os = os_idx + u.Client = client_idx + u.Version = ver + u.RemoteAddr = strings.Split(u.RemoteAddr, ":")[0] + // remove extra characters + infoSlice := strings.Split(u.Info, " ") + infoLen := len(infoSlice) + if infoLen > 1 { + if u.Username == infoSlice[0] { + u.Info = strings.Join(infoSlice[1:], " ") + } + // delete - char + if infoLen > 2 && infoSlice[1] == "-" { + u.Info = u.Info[2:] + } + } + UserActLogIns.Pool.JobQueue <- func() { + _ = Add(u) + } +} + +// 转义操作类型, 方便vue显示 +func (ua *UserActLogProcess) GetStatusOpsWithTag() interface{} { + type StatusTag struct { + Key int `json:"key"` + Value string `json:"value"` + Tag string `json:"tag"` + } + var res []StatusTag + for k, v := range ua.StatusOps { + tag := "info" + switch k { + case UserAuthFail: + tag = "danger" + case UserAuthSuccess: + tag = "success" + case UserConnected: + tag = "" + } + res = append(res, StatusTag{k, v, tag}) + } + return res +} + +func (ua *UserActLogProcess) GetInfoOpsById(id uint8) string { + infoMap := ua.InfoOps + return infoMap[id] +} + +func (ua *UserActLogProcess) ParseUserAgent(userAgent string) (os_idx, client_idx uint8, ver string) { + // os + os_idx = 2 + if strings.Contains(userAgent, "windows") { + os_idx = 0 + } else if strings.Contains(userAgent, "mac os") || strings.Contains(userAgent, "darwin_i386") { + os_idx = 1 + } else if strings.Contains(userAgent, "darwin_arm") || strings.Contains(userAgent, "apple") { + os_idx = 4 + } else if strings.Contains(userAgent, "android") { + os_idx = 3 + } + // client + client_idx = 2 + if strings.Contains(userAgent, "anyconnect") { + client_idx = 0 + } else if strings.Contains(userAgent, "openconnect") { + client_idx = 1 + } + // ver + uaSlice := strings.Split(userAgent, " ") + ver = uaSlice[len(uaSlice)-1] + if ver[0] == 'v' { + ver = ver[1:] + } + if !regexp.MustCompile(`^(\d+\.?)+$`).MatchString(ver) { + ver = "" + } + return +} + +// 清除用户操作日志 +func (ua *UserActLogProcess) ClearUserActLog(ts string) (int64, error) { + affected, err := xdb.Where("created_at < '" + ts + "'").Delete(&UserActLog{}) + return affected, err +} + +// 后台筛选用户操作日志 +func (ua *UserActLogProcess) GetSession(values url.Values) *xorm.Session { + session := xdb.Where("1=1") + if values.Get("username") != "" { + session.And("username = ?", values.Get("username")) + } + if values.Get("sdate") != "" { + session.And("created_at >= ?", values.Get("sdate")+" 00:00:00'") + } + if values.Get("edate") != "" { + session.And("created_at <= ?", values.Get("edate")+" 23:59:59'") + } + if values.Get("status") != "" { + session.And("status = ?", cast.ToUint8(values.Get("status"))-1) + } + if values.Get("os") != "" { + session.And("os = ?", cast.ToUint8(values.Get("os"))-1) + } + if values.Get("sort") == "1" { + session.OrderBy("id desc") + } else { + session.OrderBy("id asc") + } + return session +} diff --git a/server/dbdata/user_act_log_test.go b/server/dbdata/user_act_log_test.go new file mode 100644 index 0000000..0628a8b --- /dev/null +++ b/server/dbdata/user_act_log_test.go @@ -0,0 +1,72 @@ +package dbdata + +import "testing" + +func TestParseUserAgent(t *testing.T) { + type args struct { + userAgent string + } + type res struct { + os_idx uint8 + client_idx uint8 + ver string + } + tests := []struct { + name string + args args + want res + }{ + { + name: "mac os 1", + args: args{userAgent: "cisco anyconnect vpn agent for mac os x 4.10.05085"}, + want: res{os_idx: 1, client_idx: 0, ver: "4.10.05085"}, + }, + { + name: "mac os 2", + args: args{userAgent: "anyconnect darwin_i386 4.10.05085"}, + want: res{os_idx: 1, client_idx: 0, ver: "4.10.05085"}, + }, + { + name: "windows", + args: args{userAgent: "cisco anyconnect vpn agent for windows 4.8.02042"}, + want: res{os_idx: 0, client_idx: 0, ver: "4.8.02042"}, + }, + { + name: "iPad", + args: args{userAgent: "anyconnect applesslvpn_darwin_arm (ipad) 4.10.04060"}, + want: res{os_idx: 4, client_idx: 0, ver: "4.10.04060"}, + }, + { + name: "iPhone", + args: args{userAgent: "cisco anyconnect vpn agent for apple iphone 4.10.04060"}, + want: res{os_idx: 4, client_idx: 0, ver: "4.10.04060"}, + }, + { + name: "android", + args: args{userAgent: "anyconnect android 4.10.05096"}, + want: res{os_idx: 3, client_idx: 0, ver: "4.10.05096"}, + }, + { + name: "linux", + args: args{userAgent: "open anyconnect vpn agent v7.08"}, + want: res{os_idx: 2, client_idx: 0, ver: "7.08"}, + }, + { + name: "openconnect", + args: args{userAgent: "openconnect-gui 1.5.3 v7.08"}, + want: res{os_idx: 2, client_idx: 1, ver: "7.08"}, + }, + { + name: "unknown", + args: args{userAgent: "unknown 1.4.3 aabcd"}, + want: res{os_idx: 2, client_idx: 2, ver: ""}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if os_idx, client_idx, ver := UserActLogIns.ParseUserAgent(tt.args.userAgent); os_idx != tt.want.os_idx || client_idx != tt.want.client_idx || ver != tt.want.ver { + t.Errorf("ParseUserAgent() = %v, %v, %v, want %v, %v, %v", os_idx, client_idx, ver, tt.want.os_idx, tt.want.client_idx, tt.want.ver) + } + }) + } +} diff --git a/server/handler/link_auth.go b/server/handler/link_auth.go index 5a8138d..279f6f5 100644 --- a/server/handler/link_auth.go +++ b/server/handler/link_auth.go @@ -66,16 +66,27 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) return } - + // 用户活动日志 + ua := dbdata.UserActLog{ + Username: cr.Auth.Username, + GroupName: cr.GroupSelect, + RemoteAddr: r.RemoteAddr, + Status: dbdata.UserAuthSuccess, + } // TODO 用户密码校验 err = dbdata.CheckUser(cr.Auth.Username, cr.Auth.Password, cr.GroupSelect) if err != nil { base.Warn(err) + ua.Info = err.Error() + ua.Status = dbdata.UserAuthFail + dbdata.UserActLogIns.Add(ua, userAgent) + w.WriteHeader(http.StatusOK) data := RequestData{Group: cr.GroupSelect, Groups: dbdata.GetGroupNames(), Error: "用户名或密码错误"} tplRequest(tpl_request, w, data) return } + dbdata.UserActLogIns.Add(ua, userAgent) // if !ok { // w.WriteHeader(http.StatusOK) // data := RequestData{Group: cr.GroupSelect, Groups: base.Cfg.UserGroups, Error: "请先激活用户"} @@ -109,7 +120,7 @@ func LinkAuth(w http.ResponseWriter, r *http.Request) { Banner: other.Banner, ProfileHash: profileHash} w.WriteHeader(http.StatusOK) tplRequest(tpl_complete, w, rd) - base.Debug("login", cr.Auth.Username) + base.Debug("login", cr.Auth.Username, userAgent) } const ( diff --git a/server/handler/link_cstp.go b/server/handler/link_cstp.go index 97a9fb3..29be380 100644 --- a/server/handler/link_cstp.go +++ b/server/handler/link_cstp.go @@ -55,6 +55,7 @@ func LinkCstp(conn net.Conn, bufRW *bufio.ReadWriter, cSess *sessdata.ConnSessio // do nothing // base.Debug("recv keepalive", cSess.IpAddr) case 0x05: // DISCONNECT + cSess.UserDisconnect = true base.Debug("DISCONNECT", cSess.IpAddr) return case 0x03: // DPD-REQ diff --git a/server/handler/link_dtls.go b/server/handler/link_dtls.go index 23c6e86..7477127 100644 --- a/server/handler/link_dtls.go +++ b/server/handler/link_dtls.go @@ -57,6 +57,7 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) { // do nothing // base.Debug("recv keepalive", cSess.IpAddr) case 0x05: // DISCONNECT + cSess.UserDisconnect = true base.Debug("DISCONNECT DTLS", cSess.IpAddr) return case 0x03: // DPD-REQ diff --git a/server/handler/link_tunnel.go b/server/handler/link_tunnel.go index 16373b2..30d9fc4 100644 --- a/server/handler/link_tunnel.go +++ b/server/handler/link_tunnel.go @@ -69,6 +69,7 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) { cSess.SetMtu(cstpMtu) cSess.MasterSecret = masterSecret cSess.RemoteAddr = r.RemoteAddr + cSess.UserAgent = strings.ToLower(r.UserAgent()) cSess.LocalIp = net.ParseIP(localIp) cstpKeepalive := base.Cfg.CstpKeepalive cstpDpd := base.Cfg.CstpDpd @@ -194,6 +195,13 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) { base.Error(err) return } + dbdata.UserActLogIns.Add(dbdata.UserActLog{ + Username: sess.Username, + GroupName: sess.Group, + IpAddr: cSess.IpAddr.String(), + RemoteAddr: cSess.RemoteAddr, + Status: dbdata.UserConnected, + }, cSess.UserAgent) go LinkCstp(conn, bufRW, cSess) } diff --git a/server/sessdata/session.go b/server/sessdata/session.go index 2da2ef4..baddab2 100644 --- a/server/sessdata/session.go +++ b/server/sessdata/session.go @@ -36,6 +36,9 @@ type ConnSession struct { Mtu int IfName string Client string // 客户端 mobile pc + UserAgent string // 客户端信息 + UserDisconnect bool // 用户/客户端主动登出 + UserKickout bool // 被踢下线 CstpDpd int Group *dbdata.Group Limit *LimitRater @@ -241,6 +244,7 @@ func (cs *ConnSession) Close() { ReleaseIp(cs.IpAddr, cs.Sess.MacAddr) LimitClient(cs.Username, true) + AddUserActLog(cs) }) } @@ -396,6 +400,7 @@ func CloseSess(token string) { } delete(sessions, token) + sess.CSess.UserKickout = true sess.CSess.Close() } @@ -418,3 +423,22 @@ func DelSessByStoken(stoken string) { delete(sessions, token) sessMux.Unlock() } + +func AddUserActLog(cs *ConnSession) { + ua := dbdata.UserActLog{ + Username: cs.Sess.Username, + GroupName: cs.Sess.Group, + IpAddr: cs.IpAddr.String(), + RemoteAddr: cs.RemoteAddr, + Status: dbdata.UserLogout, + } + infoId := uint8(0) + switch { + case cs.UserDisconnect: + infoId = 1 + case cs.UserKickout: + infoId = 2 + } + ua.Info = dbdata.UserActLogIns.GetInfoOpsById(infoId) + dbdata.UserActLogIns.Add(ua, cs.UserAgent) +} diff --git a/web/src/components/audit/Access.vue b/web/src/components/audit/Access.vue new file mode 100644 index 0000000..bdab61b --- /dev/null +++ b/web/src/components/audit/Access.vue @@ -0,0 +1,321 @@ + + + + + \ No newline at end of file diff --git a/web/src/components/audit/ActLog.vue b/web/src/components/audit/ActLog.vue new file mode 100644 index 0000000..5a18c0d --- /dev/null +++ b/web/src/components/audit/ActLog.vue @@ -0,0 +1,256 @@ + + + + + \ No newline at end of file diff --git a/web/src/pages/set/Audit.vue b/web/src/pages/set/Audit.vue index 4e3a19e..10fa366 100644 --- a/web/src/pages/set/Audit.vue +++ b/web/src/pages/set/Audit.vue @@ -1,300 +1,61 @@ - - From c8b34bd772e90ecb2091b9bbf20923604685ec24 Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Fri, 4 Nov 2022 16:30:07 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dtest=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/dbdata/user_act_log.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/dbdata/user_act_log.go b/server/dbdata/user_act_log.go index 0f956c6..a7032dd 100644 --- a/server/dbdata/user_act_log.go +++ b/server/dbdata/user_act_log.go @@ -40,11 +40,12 @@ var ( 2: "Linux", 3: "Android", 4: "iOS", + 5: "Unknown", }, ClientOps: []string{ // 客户端 0: "AnyConnect", 1: "OpenConnect", - 2: "unknown", + 2: "Unknown", }, InfoOps: []string{ // 信息 0: "用户掉线", @@ -56,6 +57,7 @@ var ( // 异步写入用户操作日志 func (ua *UserActLogProcess) Add(u UserActLog, userAgent string) { + // os, client, ver os_idx, client_idx, ver := ua.ParseUserAgent(userAgent) u.Os = os_idx u.Client = client_idx @@ -107,6 +109,10 @@ func (ua *UserActLogProcess) GetInfoOpsById(id uint8) string { } func (ua *UserActLogProcess) ParseUserAgent(userAgent string) (os_idx, client_idx uint8, ver string) { + // Unknown + if len(userAgent) == 0 { + return 5, 2, "" + } // os os_idx = 2 if strings.Contains(userAgent, "windows") { From ea5e31fd39eaae3f055bb9a0b595c18cdc73be14 Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Mon, 7 Nov 2022 18:33:20 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E6=97=A5=E5=BF=97API=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/admin/api_user_act.go | 34 ++++++++++++++++++++++++++++++++++ server/admin/server.go | 1 + 2 files changed, 35 insertions(+) create mode 100644 server/admin/api_user_act.go diff --git a/server/admin/api_user_act.go b/server/admin/api_user_act.go new file mode 100644 index 0000000..fc29498 --- /dev/null +++ b/server/admin/api_user_act.go @@ -0,0 +1,34 @@ +package admin + +import ( + "net/http" + "strconv" + + "github.com/bjdgyc/anylink/dbdata" +) + +func UserActLogList(w http.ResponseWriter, r *http.Request) { + _ = r.ParseForm() + pageS := r.FormValue("page") + page, _ := strconv.Atoi(pageS) + if page < 1 { + page = 1 + } + var datas []dbdata.UserActLog + session := dbdata.UserActLogIns.GetSession(r.Form) + count, err := dbdata.FindAndCount(session, &datas, dbdata.PageSize, page) + if err != nil && !dbdata.CheckErrNotFound(err) { + RespError(w, RespInternalErr, err) + return + } + data := map[string]interface{}{ + "count": count, + "page_size": dbdata.PageSize, + "datas": datas, + "statusOps": dbdata.UserActLogIns.GetStatusOpsWithTag(), + "osOps": dbdata.UserActLogIns.OsOps, + "clientOps": dbdata.UserActLogIns.ClientOps, + } + + RespSucess(w, data) +} diff --git a/server/admin/server.go b/server/admin/server.go index 50a24ce..5230096 100644 --- a/server/admin/server.go +++ b/server/admin/server.go @@ -63,6 +63,7 @@ func StartAdmin() { r.HandleFunc("/user/policy/detail", PolicyDetail) r.HandleFunc("/user/policy/set", PolicySet) r.HandleFunc("/user/policy/del", PolicyDel) + r.HandleFunc("/user/act_log/list", UserActLogList) r.HandleFunc("/group/list", GroupList) r.HandleFunc("/group/names", GroupNames) From 5ef13b1bffb602c0158995a25431db978156ab97 Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Tue, 8 Nov 2022 12:22:58 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BC=98=E5=8C=96CloseSess=E7=9A=84?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/admin/api_user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/admin/api_user.go b/server/admin/api_user.go index 392b8d3..a869da3 100644 --- a/server/admin/api_user.go +++ b/server/admin/api_user.go @@ -178,7 +178,7 @@ func UserOnline(w http.ResponseWriter, r *http.Request) { func UserOffline(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() token := r.FormValue("token") - sessdata.CloseSess(token, 4) + sessdata.CloseSess(token, dbdata.UserLogoutAdmin) RespSucess(w, nil) } From 32ce3f04d033f03085ac986da0fcc67b54d8d614 Mon Sep 17 00:00:00 2001 From: lanrenwo Date: Tue, 8 Nov 2022 16:35:28 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9[=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E4=BF=A1=E6=81=AF]=E8=8F=9C=E5=8D=95=E7=9A=84=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/layout/LayoutAside.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/src/layout/LayoutAside.vue b/web/src/layout/LayoutAside.vue index 332190a..cfbbc59 100644 --- a/web/src/layout/LayoutAside.vue +++ b/web/src/layout/LayoutAside.vue @@ -56,7 +56,7 @@ 用户组列表 - +