Merge pull request #159 from wsczx/dev

新增本地用户过期时间设置
This commit is contained in:
bjdgyc 2022-10-18 17:41:25 +08:00 committed by GitHub
commit 522f723b51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 81 additions and 14 deletions

View File

@ -107,7 +107,8 @@ func UserSet(w http.ResponseWriter, r *http.Request) {
return
}
}
//修改用户资料后执行过期用户检测
sessdata.CloseUserLimittimeSession()
RespSucess(w, nil)
}

View File

@ -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()
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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{}

View File

@ -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

View File

@ -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=

View File

@ -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)
}

View File

@ -1,5 +1,6 @@
// AnyLink 是一个企业级远程办公vpn软件可以支持多人同时在线使用。
//go:build !windows
// +build !windows
package main

View File

@ -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)

View File

@ -4,4 +4,5 @@ func Start() {
initIpPool()
checkSession()
saveStatsInfo()
CloseUserLimittimeSession()
}

View File

@ -87,7 +87,8 @@
width="70">
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 1" type="success">可用</el-tag>
<el-tag v-else type="danger">停用</el-tag>
<el-tag v-if="scope.row.status === 0" type="danger">停用</el-tag>
<el-tag v-if="scope.row.status === 2" >过期</el-tag>
</template>
</el-table-column>
@ -182,6 +183,17 @@
<el-input v-model="ruleForm.pin_code" placeholder="不填由系统自动生成"></el-input>
</el-form-item>
<el-form-item label="过期时间" prop="limittime">
<el-date-picker
v-model="ruleForm.limittime"
type="date"
size="small"
align="center"
style="width:130px"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
<el-form-item label="禁用OTP" prop="disable_otp">
<el-switch
v-model="ruleForm.disable_otp">
@ -208,6 +220,7 @@
<el-radio-group v-model="ruleForm.status">
<el-radio :label="1" border>启用</el-radio>
<el-radio :label="0" border>停用</el-radio>
<el-radio :label="2" border>过期</el-radio>
</el-radio-group>
</el-form-item>
@ -264,7 +277,6 @@ export default {
{required: true, message: '请输入用户邮箱', trigger: 'blur'},
{type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change']}
],
password: [
{min: 6, message: '长度大于 6 个字符', trigger: 'blur'}
],