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'}
],