mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 03:07:20 +08:00
feat: 优化会话机制
This commit is contained in:
@@ -55,8 +55,7 @@ func initWeb() (*app.Web, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger := bootstrap.NewLog(koanf)
|
||||
db, err := bootstrap.NewDB(koanf, logger)
|
||||
db, err := bootstrap.NewDB(koanf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -65,11 +64,12 @@ func initWeb() (*app.Web, error) {
|
||||
return nil, err
|
||||
}
|
||||
cacheRepo := data.NewCacheRepo(db)
|
||||
logger := bootstrap.NewLog(koanf)
|
||||
queue := bootstrap.NewQueue()
|
||||
taskRepo := data.NewTaskRepo(locale, db, logger, queue)
|
||||
appRepo := data.NewAppRepo(locale, koanf, db, cacheRepo, taskRepo)
|
||||
userTokenRepo := data.NewUserTokenRepo(locale, db)
|
||||
middlewares := middleware.NewMiddlewares(koanf, logger, manager, appRepo, userTokenRepo)
|
||||
middlewares := middleware.NewMiddlewares(koanf, manager, appRepo, userTokenRepo)
|
||||
userRepo := data.NewUserRepo(locale, db)
|
||||
userService := service.NewUserService(locale, koanf, manager, userRepo)
|
||||
userTokenService := service.NewUserTokenService(locale, userTokenRepo)
|
||||
|
||||
@@ -53,12 +53,12 @@ func initCli() (*app.Cli, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger := bootstrap.NewLog(koanf)
|
||||
db, err := bootstrap.NewDB(koanf, logger)
|
||||
db, err := bootstrap.NewDB(koanf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheRepo := data.NewCacheRepo(db)
|
||||
logger := bootstrap.NewLog(koanf)
|
||||
queue := bootstrap.NewQueue()
|
||||
taskRepo := data.NewTaskRepo(locale, db, logger, queue)
|
||||
appRepo := data.NewAppRepo(locale, koanf, db, cacheRepo, taskRepo)
|
||||
|
||||
4
go.mod
4
go.mod
@@ -35,8 +35,8 @@ require (
|
||||
github.com/libdns/tencentcloud v1.4.2
|
||||
github.com/libdns/westcn v1.0.2
|
||||
github.com/libtnb/chix v1.3.0
|
||||
github.com/libtnb/gormstore v1.1.0
|
||||
github.com/libtnb/sessions v1.2.0
|
||||
github.com/libtnb/gormstore v1.1.1
|
||||
github.com/libtnb/sessions v1.2.1
|
||||
github.com/libtnb/utils v1.2.0
|
||||
github.com/mholt/acmez/v3 v3.1.3
|
||||
github.com/ncruces/go-sqlite3 v0.29.0
|
||||
|
||||
10
go.sum
10
go.sum
@@ -106,6 +106,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
|
||||
github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
@@ -218,10 +220,14 @@ github.com/libtnb/chix v1.3.0 h1:/U+CyuxI41ooeB6M/762PHOjQlfHRg6BQjHKLZarlrM=
|
||||
github.com/libtnb/chix v1.3.0/go.mod h1:o8nQLEp/UrUojBKYzw8K8sltU/h0XxI2VLZ/z7AQCQg=
|
||||
github.com/libtnb/gormstore v1.1.0 h1:VbX8u0hhyl2YFSGfkSlF/xSfFG/LE29DCLrY8MJ+uxM=
|
||||
github.com/libtnb/gormstore v1.1.0/go.mod h1:8A5QzeZxi1MpSmjUVsHTDAL6KnU84feIXMutFLPawwA=
|
||||
github.com/libtnb/gormstore v1.1.1 h1:FG/3P4PuWM6/vB4weVJ31meiSaoeXns1NQlP66quKeg=
|
||||
github.com/libtnb/gormstore v1.1.1/go.mod h1:8A5QzeZxi1MpSmjUVsHTDAL6KnU84feIXMutFLPawwA=
|
||||
github.com/libtnb/securecookie v1.2.0 h1:2uc0PBDm0foeSTrcZ9QTX1IEjf6kFEwfgEYSIXQSKrA=
|
||||
github.com/libtnb/securecookie v1.2.0/go.mod h1:ja+wNGnQzYqcqXQnJWu6icsaWi5JEBwNEMJ2ReTVDxA=
|
||||
github.com/libtnb/sessions v1.2.0 h1:g/RMcfGTC5P2BQE1IqrgppPEQ++x/QjOuiwbN9Frke8=
|
||||
github.com/libtnb/sessions v1.2.0/go.mod h1:45Bn9d6PseDINLIM1QaJrlCMbzSZ0NWpDbWkdrKJKw0=
|
||||
github.com/libtnb/sessions v1.2.1 h1:O9gkEIeZuqyaxopXrUJcGxlNxmNfRBI8BOK43yLJXDI=
|
||||
github.com/libtnb/sessions v1.2.1/go.mod h1:45Bn9d6PseDINLIM1QaJrlCMbzSZ0NWpDbWkdrKJKw0=
|
||||
github.com/libtnb/utils v1.2.0 h1:6bTZrWn2OkNrODpCY4dhuHwbhsVRV7HICIgmZ31we98=
|
||||
github.com/libtnb/utils v1.2.0/go.mod h1:9gSEuhkADlvYbM3qJRQUAMC5ypMrhrYpX9YMuYJ6ws8=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
@@ -374,6 +380,8 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -446,6 +454,8 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
||||
@@ -9,16 +9,29 @@ import (
|
||||
_ "github.com/ncruces/go-sqlite3/embed"
|
||||
"github.com/ncruces/go-sqlite3/gormlite"
|
||||
sloggorm "github.com/orandin/slog-gorm"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/tnborg/panel/internal/app"
|
||||
"github.com/tnborg/panel/internal/migration"
|
||||
)
|
||||
|
||||
func NewDB(conf *koanf.Koanf, log *slog.Logger) (*gorm.DB, error) {
|
||||
// You can use any other database, like MySQL or PostgreSQL.
|
||||
func NewDB(conf *koanf.Koanf) (*gorm.DB, error) {
|
||||
ljLogger := &lumberjack.Logger{
|
||||
Filename: filepath.Join(app.Root, "panel/storage/logs/db.log"),
|
||||
MaxSize: 10,
|
||||
MaxAge: 30,
|
||||
Compress: true,
|
||||
}
|
||||
|
||||
handler := slog.New(slog.NewJSONHandler(ljLogger, nil)).Handler()
|
||||
options := []sloggorm.Option{sloggorm.WithHandler(handler)}
|
||||
if conf.Bool("database.debug") {
|
||||
options = append(options, sloggorm.WithTraceAll())
|
||||
}
|
||||
|
||||
return gorm.Open(gormlite.Open("file:"+filepath.Join(app.Root, "panel/storage/app.db?_txlock=immediate")), &gorm.Config{
|
||||
Logger: sloggorm.New(sloggorm.WithHandler(log.Handler())),
|
||||
Logger: sloggorm.New(options...),
|
||||
SkipDefaultTransaction: true,
|
||||
DisableForeignKeyConstraintWhenMigrating: true,
|
||||
})
|
||||
|
||||
@@ -10,10 +10,6 @@ import (
|
||||
func NewSession(conf *koanf.Koanf, db *gorm.DB) (*sessions.Manager, error) {
|
||||
// initialize session manager
|
||||
lifetime := conf.Int("session.lifetime")
|
||||
// TODO: will remove this fallback in v3
|
||||
if lifetime == 0 {
|
||||
lifetime = 120
|
||||
}
|
||||
manager, err := sessions.NewManager(&sessions.ManagerOptions{
|
||||
Key: conf.MustString("app.key"),
|
||||
Lifetime: lifetime,
|
||||
|
||||
@@ -3,6 +3,7 @@ package middleware
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
@@ -12,6 +13,8 @@ import (
|
||||
"github.com/leonelquinteros/gotext"
|
||||
"github.com/libtnb/sessions"
|
||||
sessionmiddleware "github.com/libtnb/sessions/middleware"
|
||||
"github.com/tnborg/panel/internal/app"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
"github.com/tnborg/panel/internal/biz"
|
||||
)
|
||||
@@ -22,16 +25,23 @@ type Middlewares struct {
|
||||
conf *koanf.Koanf
|
||||
log *slog.Logger
|
||||
session *sessions.Manager
|
||||
app biz.AppRepo
|
||||
appRepo biz.AppRepo
|
||||
userToken biz.UserTokenRepo
|
||||
}
|
||||
|
||||
func NewMiddlewares(conf *koanf.Koanf, log *slog.Logger, session *sessions.Manager, app biz.AppRepo, userToken biz.UserTokenRepo) *Middlewares {
|
||||
func NewMiddlewares(conf *koanf.Koanf, session *sessions.Manager, appRepo biz.AppRepo, userToken biz.UserTokenRepo) *Middlewares {
|
||||
ljLogger := &lumberjack.Logger{
|
||||
Filename: filepath.Join(app.Root, "panel/storage/logs/http.log"),
|
||||
MaxSize: 10,
|
||||
MaxAge: 30,
|
||||
Compress: true,
|
||||
}
|
||||
|
||||
return &Middlewares{
|
||||
conf: conf,
|
||||
log: log,
|
||||
log: slog.New(slog.NewJSONHandler(ljLogger, &slog.HandlerOptions{Level: slog.LevelInfo})),
|
||||
session: session,
|
||||
app: app,
|
||||
appRepo: appRepo,
|
||||
userToken: userToken,
|
||||
}
|
||||
}
|
||||
@@ -50,6 +60,6 @@ func (r *Middlewares) Globals(t *gotext.Locale, mux *chi.Mux) []func(http.Handle
|
||||
Status(t),
|
||||
Entrance(t, r.conf, r.session),
|
||||
MustLogin(t, r.session, r.userToken),
|
||||
MustInstall(t, r.app),
|
||||
MustInstall(t, r.appRepo),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/leonelquinteros/gotext"
|
||||
"github.com/libtnb/sessions"
|
||||
@@ -72,6 +73,20 @@ func MustLogin(t *gotext.Locale, session *sessions.Manager, userToken biz.UserTo
|
||||
}
|
||||
|
||||
userID = cast.ToUint(sess.Get("user_id"))
|
||||
refreshAt := cast.ToInt64(sess.Get("refresh_at")) // 上次刷新的时间戳
|
||||
// 距离上次刷新时间超过 10 分钟刷新 Cookie 有效期
|
||||
if time.Now().Unix()-refreshAt > 600 {
|
||||
sess.Put("refresh_at", time.Now().Unix())
|
||||
// 重新设置 Cookie
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: sess.GetName(),
|
||||
Value: sess.GetID(),
|
||||
Expires: time.Now().Add(time.Duration(session.Lifetime) * time.Minute),
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if userID == 0 {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/knadh/koanf/v2"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
@@ -98,6 +99,12 @@ func (s *UserService) Login(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 重新生成会话 ID
|
||||
if err = sess.Regenerate(true); err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 安全登录下,将当前客户端与会话绑定
|
||||
// 安全登录只在未启用面板 HTTPS 时生效
|
||||
ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr))
|
||||
@@ -114,6 +121,7 @@ func (s *UserService) Login(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
sess.Put("user_id", user.ID)
|
||||
sess.Put("refresh_at", time.Now().Unix())
|
||||
sess.Forget("key")
|
||||
Success(w, nil)
|
||||
}
|
||||
@@ -129,6 +137,12 @@ func (s *UserService) Logout(w http.ResponseWriter, r *http.Request) {
|
||||
sess.Forget("safe_login")
|
||||
sess.Forget("safe_client")
|
||||
|
||||
// 重新生成会话 ID
|
||||
if err = sess.Regenerate(true); err != nil {
|
||||
Error(w, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
Success(w, nil)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user