diff --git a/server/admin/api_user.go b/server/admin/api_user.go index 516d3ae..f58efe9 100644 --- a/server/admin/api_user.go +++ b/server/admin/api_user.go @@ -107,7 +107,8 @@ func UserSet(w http.ResponseWriter, r *http.Request) { return } } - + //修改用户资料后执行过期用户检测 + sessdata.CloseUserLimittimeSession() RespSucess(w, nil) } diff --git a/server/cron/start.go b/server/cron/start.go index 2692cfe..96159ab 100644 --- a/server/cron/start.go +++ b/server/cron/start.go @@ -3,6 +3,7 @@ package cron import ( "time" + "github.com/bjdgyc/anylink/sessdata" "github.com/go-co-op/gocron" ) @@ -10,5 +11,6 @@ func Start() { s := gocron.NewScheduler(time.Local) s.Cron("0 * * * *").Do(ClearAudit) s.Cron("0 * * * *").Do(ClearStatsInfo) + s.Every(1).Day().At("00:00").Do(sessdata.CloseUserLimittimeSession) s.StartAsync() } diff --git a/server/dbdata/db.go b/server/dbdata/db.go index 64f1ecc..d65266b 100644 --- a/server/dbdata/db.go +++ b/server/dbdata/db.go @@ -1,6 +1,8 @@ package dbdata import ( + "time" + "github.com/bjdgyc/anylink/base" _ "github.com/go-sql-driver/mysql" _ "github.com/lib/pq" @@ -19,6 +21,9 @@ func GetXdb() *xorm.Engine { func initDb() { var err error xdb, err = xorm.NewEngine(base.Cfg.DbType, base.Cfg.DbSource) + // 初始化xorm时区 + xdb.DatabaseTZ = time.Local + xdb.TZLocation = time.Local if err != nil { base.Fatal(err) } diff --git a/server/dbdata/tables.go b/server/dbdata/tables.go index e0da7e0..53dff7a 100644 --- a/server/dbdata/tables.go +++ b/server/dbdata/tables.go @@ -29,14 +29,15 @@ type User struct { Nickname string `json:"nickname" xorm:"varchar(255)"` Email string `json:"email" xorm:"varchar(255)"` // Password string `json:"password"` - PinCode string `json:"pin_code" xorm:"varchar(32)"` - OtpSecret string `json:"otp_secret" xorm:"varchar(255)"` - DisableOtp bool `json:"disable_otp" xorm:"Bool"` // 禁用otp - Groups []string `json:"groups" xorm:"Text"` - Status int8 `json:"status" xorm:"Int"` // 1正常 - SendEmail bool `json:"send_email" xorm:"Bool"` - CreatedAt time.Time `json:"created_at" xorm:"DateTime created"` - UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"` + PinCode string `json:"pin_code" xorm:"varchar(32)"` + LimitTime *time.Time `json:"limittime,omitempty" xorm:"Datetime limittime"` //值为null时,前端不显示 + OtpSecret string `json:"otp_secret" xorm:"varchar(255)"` + DisableOtp bool `json:"disable_otp" xorm:"Bool"` // 禁用otp + Groups []string `json:"groups" xorm:"Text"` + Status int8 `json:"status" xorm:"Int"` // 1正常 + SendEmail bool `json:"send_email" xorm:"Bool"` + CreatedAt time.Time `json:"created_at" xorm:"DateTime created"` + UpdatedAt time.Time `json:"updated_at" xorm:"DateTime updated"` } type IpMap struct { diff --git a/server/dbdata/user.go b/server/dbdata/user.go index 7834013..e05ab4d 100644 --- a/server/dbdata/user.go +++ b/server/dbdata/user.go @@ -104,7 +104,12 @@ func checkLocalUser(name, pwd, group string) error { v := &User{} err := One("Username", name, v) if err != nil || v.Status != 1 { - return fmt.Errorf("%s %s", name, "用户名错误") + switch v.Status { + case 0: + return fmt.Errorf("%s %s", name, "用户不存在或用户已停用") + case 2: + return fmt.Errorf("%s %s", name, "用户已过期") + } } // 判断用户组信息 if !utils.InArrStr(v.Groups, group) { @@ -128,6 +133,21 @@ func checkLocalUser(name, pwd, group string) error { return nil } +// 用户过期时间到达后,更新用户状态,并返回一个状态为过期的用户切片 +func CheckUserlimittime() (limitUser []interface{}) { + if _, err := xdb.Where("limittime <= ?", time.Now()).And("status = ?", 1).Update(&User{Status: 2}); err != nil { + return + } + user := make(map[int64]User) + if err := xdb.Where("status != ?", 1).Find(user); err != nil { + return + } + for _, v := range user { + limitUser = append(limitUser, v.Username) + } + return +} + var ( userOtpMux = sync.Mutex{} userOtp = map[string]time.Time{} diff --git a/server/go.mod b/server/go.mod index acc9e92..7aa6ebc 100644 --- a/server/go.mod +++ b/server/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/arl/statsviz v0.5.1 + github.com/deckarep/golang-set v1.8.0 github.com/go-co-op/gocron v1.17.0 github.com/go-ldap/ldap v3.0.3+incompatible github.com/go-sql-driver/mysql v1.6.0 diff --git a/server/go.sum b/server/go.sum index aa2f83a..5371b25 100644 --- a/server/go.sum +++ b/server/go.sum @@ -98,6 +98,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= +github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= diff --git a/server/handler/link_home.go b/server/handler/link_home.go index 9669d26..8359f93 100644 --- a/server/handler/link_home.go +++ b/server/handler/link_home.go @@ -21,11 +21,13 @@ func LinkHome(w http.ResponseWriter, r *http.Request) { return } index := &dbdata.SettingOther{} - dbdata.SettingGet(index) + if err := dbdata.SettingGet(index); err != nil { + return + } w.WriteHeader(http.StatusOK) if index.Homeindex == "" { index.Homeindex = "AnyLink 是一个企业级远程办公 SSL VPN 软件,可以支持多人同时在线使用。" - } + } fmt.Fprintln(w, index.Homeindex) } diff --git a/server/main.go b/server/main.go index c52ddcf..a25efc5 100644 --- a/server/main.go +++ b/server/main.go @@ -1,5 +1,6 @@ // AnyLink 是一个企业级远程办公vpn软件,可以支持多人同时在线使用。 +//go:build !windows // +build !windows package main diff --git a/server/sessdata/session.go b/server/sessdata/session.go index 70f3e7e..90af092 100644 --- a/server/sessdata/session.go +++ b/server/sessdata/session.go @@ -13,6 +13,7 @@ import ( "github.com/bjdgyc/anylink/base" "github.com/bjdgyc/anylink/dbdata" "github.com/bjdgyc/anylink/pkg/utils" + mapset "github.com/deckarep/golang-set" "github.com/ivpusic/grpool" atomic2 "go.uber.org/atomic" ) @@ -113,6 +114,24 @@ func checkSession() { }() } +// 状态为过期的用户踢下线 +func CloseUserLimittimeSession() { + s := mapset.NewSetFromSlice(dbdata.CheckUserlimittime()) + limitTimeToken := []string{} + sessMux.RLock() + for _, v := range sessions { + v.mux.RLock() + if v.IsActive && s.Contains(v.Username) { + limitTimeToken = append(limitTimeToken, v.Token) + } + v.mux.RUnlock() + } + sessMux.RUnlock() + for _, v := range limitTimeToken { + CloseSess(v) + } +} + func GenToken() string { // 生成32位的 token bToken := make([]byte, 32) diff --git a/server/sessdata/start.go b/server/sessdata/start.go index 1d4243c..7862574 100644 --- a/server/sessdata/start.go +++ b/server/sessdata/start.go @@ -4,4 +4,5 @@ func Start() { initIpPool() checkSession() saveStatsInfo() + CloseUserLimittimeSession() } diff --git a/web/src/pages/user/List.vue b/web/src/pages/user/List.vue index 45b3805..4ae0aae 100644 --- a/web/src/pages/user/List.vue +++ b/web/src/pages/user/List.vue @@ -87,7 +87,8 @@ width="70"> @@ -182,6 +183,17 @@ + + + + + @@ -208,6 +220,7 @@ 启用 停用 + 过期 @@ -264,7 +277,6 @@ export default { {required: true, message: '请输入用户邮箱', trigger: 'blur'}, {type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change']} ], - password: [ {min: 6, message: '长度大于 6 个字符', trigger: 'blur'} ],