b 4 сар өмнө
parent
commit
843c59351a

+ 7 - 12
go.mod

@@ -3,14 +3,14 @@ module git.ooo.ink/root/go-kit
 go 1.25.0
 
 require (
-	github.com/5-say/go-tool v0.6.1
 	github.com/gin-gonic/gin v1.12.0
 	github.com/golang-jwt/jwt/v5 v5.3.1
 	github.com/jinzhu/configor v1.2.2
+	github.com/natefinch/lumberjack v2.0.0+incompatible
+	github.com/rs/zerolog v1.32.0
 	github.com/stretchr/testify v1.11.1
-	gorm.io/gen v0.3.27
+	gorm.io/driver/mysql v1.5.7
 	gorm.io/gorm v1.31.1
-	gorm.io/plugin/dbresolver v1.6.2
 )
 
 require (
@@ -29,7 +29,6 @@ require (
 	github.com/go-sql-driver/mysql v1.8.1 // indirect
 	github.com/goccy/go-json v0.10.5 // indirect
 	github.com/goccy/go-yaml v1.19.2 // indirect
-	github.com/google/uuid v1.3.0 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
@@ -39,26 +38,22 @@ require (
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
 	github.com/pelletier/go-toml/v2 v2.2.4 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/quic-go/qpack v0.6.0 // indirect
 	github.com/quic-go/quic-go v0.59.0 // indirect
-	github.com/rs/zerolog v1.32.0 // indirect
+	github.com/rogpeppe/go-internal v1.12.0 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.3.1 // indirect
 	go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
 	golang.org/x/arch v0.22.0 // indirect
 	golang.org/x/crypto v0.48.0 // indirect
-	golang.org/x/mod v0.32.0 // indirect
 	golang.org/x/net v0.51.0 // indirect
-	golang.org/x/sync v0.19.0 // indirect
 	golang.org/x/sys v0.41.0 // indirect
 	golang.org/x/text v0.34.0 // indirect
-	golang.org/x/tools v0.41.0 // indirect
 	google.golang.org/protobuf v1.36.10 // indirect
+	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	gorm.io/datatypes v1.2.4 // indirect
-	gorm.io/driver/mysql v1.5.7 // indirect
-	gorm.io/hints v1.1.2 // indirect
 )

+ 1 - 45
go.sum

@@ -1,7 +1,5 @@
 filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
 filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
-github.com/5-say/go-tool v0.6.1 h1:62wCJUx83kj/vKjHxAmZaA/BP5iO4XzGeC4EdDAdWv8=
-github.com/5-say/go-tool v0.6.1/go.mod h1:XtqJJWHnhqdeGbn2IxxsYgsJehH0oydUeXymLrp79fI=
 github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
@@ -41,23 +39,9 @@ github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
 github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
-github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
-github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
-github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
-github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
 github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
 github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
-github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
-github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
-github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
-github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
-github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
 github.com/jinzhu/configor v1.2.2 h1:sLgh6KMzpCmaQB4e+9Fu/29VErtBUqsS2t8C9BNIVsA=
 github.com/jinzhu/configor v1.2.2/go.mod h1:iFFSfOBKP3kC2Dku0ZGB3t3aulfQgTGJknodhFavsU8=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@@ -80,12 +64,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
 github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
-github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
-github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
-github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
-github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
-github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -95,6 +73,7 @@ github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4
 github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
 github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -130,12 +109,8 @@ golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
 golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
 golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
 golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
-golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
-golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
 golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
 golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
-golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
-golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -143,8 +118,6 @@ golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
 golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
 golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
 golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
-golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
-golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
 google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
 google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -157,25 +130,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/datatypes v1.2.4 h1:uZmGAcK/QZ0uyfCuVg0VQY1ZmV9h1fuG0tMwKByO1z4=
-gorm.io/datatypes v1.2.4/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI=
 gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
 gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
-gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
-gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
-gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I=
-gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
-gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
-gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
-gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
-gorm.io/gen v0.3.27 h1:ziocAFLpE7e0g4Rum69pGfB9S6DweTxK8gAun7cU8as=
-gorm.io/gen v0.3.27/go.mod h1:9zquz2xD1f3Eb/eHq4oLn2z6vDVvQlCY5S3uMBLv4EA=
-gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
-gorm.io/gorm v1.25.0/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
 gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
 gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
 gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
-gorm.io/hints v1.1.2 h1:b5j0kwk5p4+3BtDtYqqfY+ATSxjj+6ptPgVveuynn9o=
-gorm.io/hints v1.1.2/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg=
-gorm.io/plugin/dbresolver v1.6.2 h1:F4b85TenghUeITqe3+epPSUtHH7RIk3fXr5l83DF8Pc=
-gorm.io/plugin/dbresolver v1.6.2/go.mod h1:tctw63jdrOezFR9HmrKnPkmig3m5Edem9fdxk9bQSzM=

+ 0 - 26
src/gin/jwtx2/CurrentAuth.go

@@ -1,26 +0,0 @@
-package jwtx
-
-import "github.com/gin-gonic/gin"
-
-type Current struct {
-	AccountID     uint64 // 账户 ID
-	LoginGroup    string // 登录的分组
-	LoginTerminal string // 登录的终端
-	MakeTokenIP   string // 首次请求生成 token 的 IP 地址
-}
-
-// 获取当前登录的账户信息,需配合中间件使用
-func CurrentAuth(c *gin.Context) Current {
-
-	var accountID uint64
-	if val, ok := c.Get("jwtx.accountID"); ok && val != nil {
-		accountID, _ = val.(uint64)
-	}
-
-	return Current{
-		AccountID:     accountID,
-		LoginGroup:    c.GetString("jwtx.loginGroup"),
-		LoginTerminal: c.GetString("jwtx.loginTerminal"),
-		MakeTokenIP:   c.GetString("jwtx.makeTokenIP"),
-	}
-}

+ 0 - 99
src/gin/jwtx2/InitGroup.go

@@ -1,99 +0,0 @@
-package jwtx
-
-import (
-	"crypto/ecdsa"
-	"time"
-
-	"github.com/5-say/go-tool/crypto/ecdsatool"
-	"github.com/5-say/go-tool/gin/jwtx/db/dao/model"
-	"github.com/5-say/go-tool/gin/jwtx/tool"
-	"github.com/5-say/go-tool/gorm/mysqlx"
-	"github.com/5-say/go-tool/logx"
-	"github.com/5-say/go-tool/utilx"
-	"github.com/jinzhu/configor"
-	"gorm.io/gorm"
-	"gorm.io/gorm/logger"
-
-	_ "embed"
-)
-
-// 初始化分组(支持多次调用)
-//
-//	group          string 分组名称
-//	configPath     string 分组配置文件路径
-//	privateKeyPath string 分组私钥文件路径
-//
-// e.g.
-//
-//	jwtx.InitGroup("admin", "jwtx/config/admin.yaml", "jwtx/config/admin.key")
-//	jwtx.InitGroup("user",  "jwtx/config/user.yaml",  "jwtx/config/user.key")
-func InitGroup(group, configPath, privateKeyPath string) *SingletonT {
-	// 配置文件不存在则创建
-	createConfigFileIfNotExist(configPath)
-
-	// 私钥文件不存在则创建
-	createKeyFileIfNotExist(privateKeyPath)
-
-	// 取得单例
-	if Singleton == nil {
-		Singleton = &SingletonT{}
-		Singleton.DB = make(map[string]*gorm.DB)
-		Singleton.Config = make(map[string]GroupConfig)
-		Singleton.PrivateKey = make(map[string]*ecdsa.PrivateKey)
-	}
-
-	// 引用简化
-	var s = Singleton
-
-	// 初始化分组配置,每秒自动更新
-	var config GroupConfig
-	err := configor.New(&configor.Config{AutoReload: true}).Load(&config, configPath)
-	if err != nil {
-		panic(err)
-	}
-	s.Config[group] = config
-
-	// 初始化分组数据库连接
-	s.DB[group], err = mysqlx.New(config.MysqlDSN, logx.GormLogger(logger.Config{
-		SlowThreshold:             200 * time.Millisecond,
-		IgnoreRecordNotFoundError: false,
-		ParameterizedQueries:      false,
-		LogLevel:                  logger.Warn,
-	}))
-	if err != nil {
-		panic(err)
-	}
-
-	// 初始化数据库结构
-	s.DB[group].AutoMigrate(&model.JwtxToken{})
-
-	// 初始化分组私钥
-	privateKey, err := tool.GetPrivateKey(privateKeyPath)
-	if err != nil {
-		panic(err)
-	}
-	s.PrivateKey[group] = privateKey
-
-	return s
-}
-
-//go:embed example/demo.yaml
-var demoConfig string
-
-func createConfigFileIfNotExist(filePath string) {
-	utilx.ForceCreateWriteIfNotExist(filePath, 0755, demoConfig)
-}
-
-func createKeyFileIfNotExist(filePath string) {
-	key, _ := ecdsatool.GenerateKey(ecdsatool.P_384)
-	privateKeyPEMBytes, _ := ecdsatool.PEM_EncodePrivateKey(key)
-	content := "\n"
-	content += "密钥格式: NIST P-384"
-	content += "\n\n"
-	content += string(privateKeyPEMBytes)
-	content += "\n"
-	content += "密钥格式: NIST P-384"
-	content += "\n"
-
-	utilx.ForceCreateWriteIfNotExist(filePath, 0755, content)
-}

+ 0 - 18
src/gin/jwtx2/README.md

@@ -1,18 +0,0 @@
-# jwtx
-
-## 跨域资源共享 CORS
-
-使用官方 cors 全局中间件,并添加以下必要配置
-
-```golang
-r.Use(cors.New(cors.Config{
-
-    // 允许跨域请求携带 Authorization 头信息
-    AllowMethods:  []string{"OPTIONS"},
-    AllowHeaders:  []string{"Authorization"},
-
-    // 允许跨域请求获取 token 响应头
-    ExposeHeaders: []string{"token"},
-}))
-```
-

+ 0 - 44
src/gin/jwtx2/Singleton.go

@@ -1,44 +0,0 @@
-package jwtx
-
-import (
-	"crypto/ecdsa"
-
-	"gorm.io/gorm"
-)
-
-// 单例
-var Singleton *SingletonT
-
-// SingletonT ..
-type SingletonT struct {
-	DB         map[string]*gorm.DB
-	Config     map[string]GroupConfig
-	PrivateKey map[string]*ecdsa.PrivateKey
-}
-
-// 分组配置
-type GroupConfig struct {
-	// consult[https://gorm.io/docs/connecting_to_the_database.html]"
-	MysqlDSN string `yaml:"MysqlDSN"`
-
-	// 是否开启 IP一致性校验,当前 IP 必须与登录时 IP 一致
-	CheckIP bool `yaml:"CheckIP"`
-	// 是否开启 单端登录
-	SingleEnd bool `yaml:"SingleEnd"`
-
-	// 刷新时间间隔(秒)
-	//
-	// 超过该时间即可触发 token 刷新、旧 token 进入容错,间隔越小安全性越高
-	RefreshInterval int64 `yaml:"RefreshInterval"`
-	// 并发容错时间(秒)
-	FaultTolerance int64 `yaml:"FaultTolerance"`
-
-	// 是否开启 自动续期
-	//
-	// 假设:单次登录有效期(7天)
-	// true  只要 7天 内有操作触发刷新,登录状态就一直延续
-	// false 不论 7天 内是否操作,7天 后必定要求重新登录
-	AutomaticRenewal bool `yaml:"AutomaticRenewal"`
-	// 单次登录有效期(小时)
-	AccessExpireByHour int64 `yaml:"AccessExpireByHour"`
-}

+ 0 - 2
src/gin/jwtx2/db/Makefile

@@ -1,2 +0,0 @@
-run:
-	gentool -c "./gen.yml"

+ 0 - 29
src/gin/jwtx2/db/dao/model/jwtx_tokens.gen.go

@@ -1,29 +0,0 @@
-// Code generated by gorm.io/gen. DO NOT EDIT.
-// Code generated by gorm.io/gen. DO NOT EDIT.
-// Code generated by gorm.io/gen. DO NOT EDIT.
-
-package model
-
-import (
-	"time"
-)
-
-const TableNameJwtxToken = "jwtx_tokens"
-
-// JwtxToken jwtx token 信息表
-type JwtxToken struct {
-	ID             uint64    `gorm:"column:id;type:bigint unsigned;primaryKey;autoIncrement:true;comment:token ID" json:"id"`                              // token ID
-	AccountID      uint64    `gorm:"column:account_id;type:bigint unsigned;not null;index:account_id,priority:1;comment:账户 ID" json:"account_id"`          // 账户 ID
-	LoginGroup     string    `gorm:"column:login_group;type:varchar(255);not null;index:login_group,priority:1;comment:登录的分组" json:"login_group"`          // 登录的分组
-	LoginTerminal  string    `gorm:"column:login_terminal;type:varchar(255);not null;index:login_terminal,priority:1;comment:登录的终端" json:"login_terminal"` // 登录的终端
-	MakeTokenIP    string    `gorm:"column:make_token_ip;type:varchar(50);not null;comment:首次请求生成 token 的 IP 地址" json:"make_token_ip"`                     // 首次请求生成 token 的 IP 地址
-	CreatedAt      time.Time `gorm:"column:created_at;type:datetime;not null;comment:创建时间" json:"created_at"`                                              // 创建时间
-	LastRefreshAt  time.Time `gorm:"column:last_refresh_at;type:datetime;not null;comment:上次的刷新时间" json:"last_refresh_at"`                                 // 上次的刷新时间
-	FinalRefreshAt time.Time `gorm:"column:final_refresh_at;type:datetime;not null;comment:最后的刷新时间" json:"final_refresh_at"`                               // 最后的刷新时间
-	ExpirationAt   time.Time `gorm:"column:expiration_at;type:datetime;not null;comment:过期时间" json:"expiration_at"`                                        // 过期时间
-}
-
-// TableName JwtxToken's table name
-func (*JwtxToken) TableName() string {
-	return TableNameJwtxToken
-}

+ 0 - 93
src/gin/jwtx2/db/dao/query/gen.go

@@ -1,93 +0,0 @@
-// Code generated by gorm.io/gen. DO NOT EDIT.
-// Code generated by gorm.io/gen. DO NOT EDIT.
-// Code generated by gorm.io/gen. DO NOT EDIT.
-
-package query
-
-import (
-	"context"
-	"database/sql"
-
-	"gorm.io/gorm"
-
-	"gorm.io/gen"
-
-	"gorm.io/plugin/dbresolver"
-)
-
-func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
-	return &Query{
-		db:        db,
-		JwtxToken: newJwtxToken(db, opts...),
-	}
-}
-
-type Query struct {
-	db *gorm.DB
-
-	JwtxToken jwtxToken
-}
-
-func (q *Query) Available() bool { return q.db != nil }
-
-func (q *Query) clone(db *gorm.DB) *Query {
-	return &Query{
-		db:        db,
-		JwtxToken: q.JwtxToken.clone(db),
-	}
-}
-
-func (q *Query) ReadDB() *Query {
-	return q.ReplaceDB(q.db.Clauses(dbresolver.Read))
-}
-
-func (q *Query) WriteDB() *Query {
-	return q.ReplaceDB(q.db.Clauses(dbresolver.Write))
-}
-
-func (q *Query) ReplaceDB(db *gorm.DB) *Query {
-	return &Query{
-		db:        db,
-		JwtxToken: q.JwtxToken.replaceDB(db),
-	}
-}
-
-type queryCtx struct {
-	JwtxToken *jwtxTokenDo
-}
-
-func (q *Query) WithContext(ctx context.Context) *queryCtx {
-	return &queryCtx{
-		JwtxToken: q.JwtxToken.WithContext(ctx),
-	}
-}
-
-func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {
-	return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
-}
-
-func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {
-	tx := q.db.Begin(opts...)
-	return &QueryTx{Query: q.clone(tx), Error: tx.Error}
-}
-
-type QueryTx struct {
-	*Query
-	Error error
-}
-
-func (q *QueryTx) Commit() error {
-	return q.db.Commit().Error
-}
-
-func (q *QueryTx) Rollback() error {
-	return q.db.Rollback().Error
-}
-
-func (q *QueryTx) SavePoint(name string) error {
-	return q.db.SavePoint(name).Error
-}
-
-func (q *QueryTx) RollbackTo(name string) error {
-	return q.db.RollbackTo(name).Error
-}

+ 0 - 362
src/gin/jwtx2/db/dao/query/jwtx_tokens.gen.go

@@ -1,362 +0,0 @@
-// Code generated by gorm.io/gen. DO NOT EDIT.
-// Code generated by gorm.io/gen. DO NOT EDIT.
-// Code generated by gorm.io/gen. DO NOT EDIT.
-
-package query
-
-import (
-	"context"
-
-	"gorm.io/gorm"
-	"gorm.io/gorm/clause"
-	"gorm.io/gorm/schema"
-
-	"gorm.io/gen"
-	"gorm.io/gen/field"
-
-	"gorm.io/plugin/dbresolver"
-
-	"github.com/5-say/go-tool/gin/jwtx/db/dao/model"
-)
-
-func newJwtxToken(db *gorm.DB, opts ...gen.DOOption) jwtxToken {
-	_jwtxToken := jwtxToken{}
-
-	_jwtxToken.jwtxTokenDo.UseDB(db, opts...)
-	_jwtxToken.jwtxTokenDo.UseModel(&model.JwtxToken{})
-
-	tableName := _jwtxToken.jwtxTokenDo.TableName()
-	_jwtxToken.ALL = field.NewAsterisk(tableName)
-	_jwtxToken.ID = field.NewUint64(tableName, "id")
-	_jwtxToken.AccountID = field.NewUint64(tableName, "account_id")
-	_jwtxToken.LoginGroup = field.NewString(tableName, "login_group")
-	_jwtxToken.LoginTerminal = field.NewString(tableName, "login_terminal")
-	_jwtxToken.MakeTokenIP = field.NewString(tableName, "make_token_ip")
-	_jwtxToken.CreatedAt = field.NewTime(tableName, "created_at")
-	_jwtxToken.LastRefreshAt = field.NewTime(tableName, "last_refresh_at")
-	_jwtxToken.FinalRefreshAt = field.NewTime(tableName, "final_refresh_at")
-	_jwtxToken.ExpirationAt = field.NewTime(tableName, "expiration_at")
-
-	_jwtxToken.fillFieldMap()
-
-	return _jwtxToken
-}
-
-// jwtxToken jwtx token 信息表
-type jwtxToken struct {
-	jwtxTokenDo jwtxTokenDo
-
-	ALL            field.Asterisk
-	ID             field.Uint64 // token ID
-	AccountID      field.Uint64 // 账户 ID
-	LoginGroup     field.String // 登录的分组
-	LoginTerminal  field.String // 登录的终端
-	MakeTokenIP    field.String // 首次请求生成 token 的 IP 地址
-	CreatedAt      field.Time   // 创建时间
-	LastRefreshAt  field.Time   // 上次的刷新时间
-	FinalRefreshAt field.Time   // 最后的刷新时间
-	ExpirationAt   field.Time   // 过期时间
-
-	fieldMap map[string]field.Expr
-}
-
-func (j jwtxToken) Table(newTableName string) *jwtxToken {
-	j.jwtxTokenDo.UseTable(newTableName)
-	return j.updateTableName(newTableName)
-}
-
-func (j jwtxToken) As(alias string) *jwtxToken {
-	j.jwtxTokenDo.DO = *(j.jwtxTokenDo.As(alias).(*gen.DO))
-	return j.updateTableName(alias)
-}
-
-func (j *jwtxToken) updateTableName(table string) *jwtxToken {
-	j.ALL = field.NewAsterisk(table)
-	j.ID = field.NewUint64(table, "id")
-	j.AccountID = field.NewUint64(table, "account_id")
-	j.LoginGroup = field.NewString(table, "login_group")
-	j.LoginTerminal = field.NewString(table, "login_terminal")
-	j.MakeTokenIP = field.NewString(table, "make_token_ip")
-	j.CreatedAt = field.NewTime(table, "created_at")
-	j.LastRefreshAt = field.NewTime(table, "last_refresh_at")
-	j.FinalRefreshAt = field.NewTime(table, "final_refresh_at")
-	j.ExpirationAt = field.NewTime(table, "expiration_at")
-
-	j.fillFieldMap()
-
-	return j
-}
-
-func (j *jwtxToken) WithContext(ctx context.Context) *jwtxTokenDo {
-	return j.jwtxTokenDo.WithContext(ctx)
-}
-
-func (j jwtxToken) TableName() string { return j.jwtxTokenDo.TableName() }
-
-func (j jwtxToken) Alias() string { return j.jwtxTokenDo.Alias() }
-
-func (j jwtxToken) Columns(cols ...field.Expr) gen.Columns { return j.jwtxTokenDo.Columns(cols...) }
-
-func (j *jwtxToken) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
-	_f, ok := j.fieldMap[fieldName]
-	if !ok || _f == nil {
-		return nil, false
-	}
-	_oe, ok := _f.(field.OrderExpr)
-	return _oe, ok
-}
-
-func (j *jwtxToken) fillFieldMap() {
-	j.fieldMap = make(map[string]field.Expr, 9)
-	j.fieldMap["id"] = j.ID
-	j.fieldMap["account_id"] = j.AccountID
-	j.fieldMap["login_group"] = j.LoginGroup
-	j.fieldMap["login_terminal"] = j.LoginTerminal
-	j.fieldMap["make_token_ip"] = j.MakeTokenIP
-	j.fieldMap["created_at"] = j.CreatedAt
-	j.fieldMap["last_refresh_at"] = j.LastRefreshAt
-	j.fieldMap["final_refresh_at"] = j.FinalRefreshAt
-	j.fieldMap["expiration_at"] = j.ExpirationAt
-}
-
-func (j jwtxToken) clone(db *gorm.DB) jwtxToken {
-	j.jwtxTokenDo.ReplaceConnPool(db.Statement.ConnPool)
-	return j
-}
-
-func (j jwtxToken) replaceDB(db *gorm.DB) jwtxToken {
-	j.jwtxTokenDo.ReplaceDB(db)
-	return j
-}
-
-type jwtxTokenDo struct{ gen.DO }
-
-func (j jwtxTokenDo) Debug() *jwtxTokenDo {
-	return j.withDO(j.DO.Debug())
-}
-
-func (j jwtxTokenDo) WithContext(ctx context.Context) *jwtxTokenDo {
-	return j.withDO(j.DO.WithContext(ctx))
-}
-
-func (j jwtxTokenDo) ReadDB() *jwtxTokenDo {
-	return j.Clauses(dbresolver.Read)
-}
-
-func (j jwtxTokenDo) WriteDB() *jwtxTokenDo {
-	return j.Clauses(dbresolver.Write)
-}
-
-func (j jwtxTokenDo) Session(config *gorm.Session) *jwtxTokenDo {
-	return j.withDO(j.DO.Session(config))
-}
-
-func (j jwtxTokenDo) Clauses(conds ...clause.Expression) *jwtxTokenDo {
-	return j.withDO(j.DO.Clauses(conds...))
-}
-
-func (j jwtxTokenDo) Returning(value interface{}, columns ...string) *jwtxTokenDo {
-	return j.withDO(j.DO.Returning(value, columns...))
-}
-
-func (j jwtxTokenDo) Not(conds ...gen.Condition) *jwtxTokenDo {
-	return j.withDO(j.DO.Not(conds...))
-}
-
-func (j jwtxTokenDo) Or(conds ...gen.Condition) *jwtxTokenDo {
-	return j.withDO(j.DO.Or(conds...))
-}
-
-func (j jwtxTokenDo) Select(conds ...field.Expr) *jwtxTokenDo {
-	return j.withDO(j.DO.Select(conds...))
-}
-
-func (j jwtxTokenDo) Where(conds ...gen.Condition) *jwtxTokenDo {
-	return j.withDO(j.DO.Where(conds...))
-}
-
-func (j jwtxTokenDo) Order(conds ...field.Expr) *jwtxTokenDo {
-	return j.withDO(j.DO.Order(conds...))
-}
-
-func (j jwtxTokenDo) Distinct(cols ...field.Expr) *jwtxTokenDo {
-	return j.withDO(j.DO.Distinct(cols...))
-}
-
-func (j jwtxTokenDo) Omit(cols ...field.Expr) *jwtxTokenDo {
-	return j.withDO(j.DO.Omit(cols...))
-}
-
-func (j jwtxTokenDo) Join(table schema.Tabler, on ...field.Expr) *jwtxTokenDo {
-	return j.withDO(j.DO.Join(table, on...))
-}
-
-func (j jwtxTokenDo) LeftJoin(table schema.Tabler, on ...field.Expr) *jwtxTokenDo {
-	return j.withDO(j.DO.LeftJoin(table, on...))
-}
-
-func (j jwtxTokenDo) RightJoin(table schema.Tabler, on ...field.Expr) *jwtxTokenDo {
-	return j.withDO(j.DO.RightJoin(table, on...))
-}
-
-func (j jwtxTokenDo) Group(cols ...field.Expr) *jwtxTokenDo {
-	return j.withDO(j.DO.Group(cols...))
-}
-
-func (j jwtxTokenDo) Having(conds ...gen.Condition) *jwtxTokenDo {
-	return j.withDO(j.DO.Having(conds...))
-}
-
-func (j jwtxTokenDo) Limit(limit int) *jwtxTokenDo {
-	return j.withDO(j.DO.Limit(limit))
-}
-
-func (j jwtxTokenDo) Offset(offset int) *jwtxTokenDo {
-	return j.withDO(j.DO.Offset(offset))
-}
-
-func (j jwtxTokenDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *jwtxTokenDo {
-	return j.withDO(j.DO.Scopes(funcs...))
-}
-
-func (j jwtxTokenDo) Unscoped() *jwtxTokenDo {
-	return j.withDO(j.DO.Unscoped())
-}
-
-func (j jwtxTokenDo) Create(values ...*model.JwtxToken) error {
-	if len(values) == 0 {
-		return nil
-	}
-	return j.DO.Create(values)
-}
-
-func (j jwtxTokenDo) CreateInBatches(values []*model.JwtxToken, batchSize int) error {
-	return j.DO.CreateInBatches(values, batchSize)
-}
-
-// Save : !!! underlying implementation is different with GORM
-// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
-func (j jwtxTokenDo) Save(values ...*model.JwtxToken) error {
-	if len(values) == 0 {
-		return nil
-	}
-	return j.DO.Save(values)
-}
-
-func (j jwtxTokenDo) First() (*model.JwtxToken, error) {
-	if result, err := j.DO.First(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.JwtxToken), nil
-	}
-}
-
-func (j jwtxTokenDo) Take() (*model.JwtxToken, error) {
-	if result, err := j.DO.Take(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.JwtxToken), nil
-	}
-}
-
-func (j jwtxTokenDo) Last() (*model.JwtxToken, error) {
-	if result, err := j.DO.Last(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.JwtxToken), nil
-	}
-}
-
-func (j jwtxTokenDo) Find() ([]*model.JwtxToken, error) {
-	result, err := j.DO.Find()
-	return result.([]*model.JwtxToken), err
-}
-
-func (j jwtxTokenDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.JwtxToken, err error) {
-	buf := make([]*model.JwtxToken, 0, batchSize)
-	err = j.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
-		defer func() { results = append(results, buf...) }()
-		return fc(tx, batch)
-	})
-	return results, err
-}
-
-func (j jwtxTokenDo) FindInBatches(result *[]*model.JwtxToken, batchSize int, fc func(tx gen.Dao, batch int) error) error {
-	return j.DO.FindInBatches(result, batchSize, fc)
-}
-
-func (j jwtxTokenDo) Attrs(attrs ...field.AssignExpr) *jwtxTokenDo {
-	return j.withDO(j.DO.Attrs(attrs...))
-}
-
-func (j jwtxTokenDo) Assign(attrs ...field.AssignExpr) *jwtxTokenDo {
-	return j.withDO(j.DO.Assign(attrs...))
-}
-
-func (j jwtxTokenDo) Joins(fields ...field.RelationField) *jwtxTokenDo {
-	for _, _f := range fields {
-		j = *j.withDO(j.DO.Joins(_f))
-	}
-	return &j
-}
-
-func (j jwtxTokenDo) Preload(fields ...field.RelationField) *jwtxTokenDo {
-	for _, _f := range fields {
-		j = *j.withDO(j.DO.Preload(_f))
-	}
-	return &j
-}
-
-func (j jwtxTokenDo) FirstOrInit() (*model.JwtxToken, error) {
-	if result, err := j.DO.FirstOrInit(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.JwtxToken), nil
-	}
-}
-
-func (j jwtxTokenDo) FirstOrCreate() (*model.JwtxToken, error) {
-	if result, err := j.DO.FirstOrCreate(); err != nil {
-		return nil, err
-	} else {
-		return result.(*model.JwtxToken), nil
-	}
-}
-
-func (j jwtxTokenDo) FindByPage(offset int, limit int) (result []*model.JwtxToken, count int64, err error) {
-	result, err = j.Offset(offset).Limit(limit).Find()
-	if err != nil {
-		return
-	}
-
-	if size := len(result); 0 < limit && 0 < size && size < limit {
-		count = int64(size + offset)
-		return
-	}
-
-	count, err = j.Offset(-1).Limit(-1).Count()
-	return
-}
-
-func (j jwtxTokenDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
-	count, err = j.Count()
-	if err != nil {
-		return
-	}
-
-	err = j.Offset(offset).Limit(limit).Scan(result)
-	return
-}
-
-func (j jwtxTokenDo) Scan(result interface{}) (err error) {
-	return j.DO.Scan(result)
-}
-
-func (j jwtxTokenDo) Delete(models ...*model.JwtxToken) (result gen.ResultInfo, err error) {
-	return j.DO.Delete(models)
-}
-
-func (j *jwtxTokenDo) withDO(do gen.Dao) *jwtxTokenDo {
-	j.DO = *do.(*gen.DO)
-	return j
-}

+ 0 - 56
src/gin/jwtx2/db/gen.yml

@@ -1,56 +0,0 @@
-version: "0.1"
-database:
-
-  # consult[https://gorm.io/docs/connecting_to_the_database.html]"
-  dsn: "root:root@tcp(mysql:3306)/dev_local_platform?charset=utf8mb4&parseTime=True&loc=Local"
-
-  # input mysql or postgres or sqlite or sqlserver. consult[https://gorm.io/docs/connecting_to_the_database.html]
-  db: "mysql"
-
-  # enter the required data table or leave it blank.You can input :
-  # 指定要生成的表名称,默认所有表
-  # tables  :
-  #   - orders
-  #   - users
-  #   - goods
-  tables:
-    - jwtx_tokens
-
-  # only generate models (without query file)
-  onlyModel: false
-
-  # specify a directory for output
-  # 指定输出目录
-  outPath: "./dao/query"
-
-  # query code file name, default: gen.go
-  # Genrated 查询代码文件名称
-  outFile: ""
-
-  # generate unit test for query code
-  # 生成单元测试
-  withUnitTest: false
-
-  # generated model code's package name
-  # 生成模型代码包名称
-  modelPkgName: ""
-
-  # generate with pointer when field is nullable
-  # 当字段允许空时用指针生成
-  fieldNullable: true
-
-  # generate with pointer when field has default value
-  # 当字段具有默认值时,使用指针生成
-  fieldCoverable: true
-
-  # generate field with gorm index tag
-  # 生成带有 gorm index 标签的字段
-  fieldWithIndexTag: true
-
-  # generate field with gorm column type tag
-  # 生成带有 gorm type 标签的字段
-  fieldWithTypeTag: true
-
-  # detect integer field's unsigned type, adjust generated data type
-  # 检测整数字段的无符号类型,调整生成的数据类型
-  fieldSignable: true

+ 0 - 19
src/gin/jwtx2/db/mysql/jwtx_tokens.sql

@@ -1,19 +0,0 @@
--- Active: 1727011634447@@mysql@3306@dev_local_platform
-
-DROP TABLE IF EXISTS `jwtx_tokens`;
-CREATE TABLE `jwtx_tokens` (
-  `id`               bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'token ID',
-  `account_id`       bigint unsigned NOT NULL                COMMENT '账户 ID',
-  `login_group`      varchar(255)    NOT NULL                COMMENT '登录的分组',
-  `login_terminal`   varchar(255)    NOT NULL                COMMENT '登录的终端',
-  `make_token_ip`    varchar(50)     NOT NULL                COMMENT '首次请求生成 token 的 IP 地址',
-  `created_at`       datetime        NOT NULL                COMMENT '创建时间',
-  `last_refresh_at`  datetime        NOT NULL                COMMENT '上次的刷新时间',
-  `final_refresh_at` datetime        NOT NULL                COMMENT '最后的刷新时间',
-  `expiration_at`    datetime        NOT NULL                COMMENT '过期时间',
-  --
-  KEY `account_id` (`account_id`),
-  KEY `login_group` (`login_group`),
-  KEY `login_terminal` (`login_terminal`),
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='jwtx token 信息表';

+ 0 - 24
src/gin/jwtx2/example/demo.yaml

@@ -1,24 +0,0 @@
-
-# consult[https://gorm.io/docs/connecting_to_the_database.html]"
-MysqlDSN : "root:root@tcp(mysql:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local"
-
-# 是否开启 IP一致性校验,当前 IP 必须与登录时 IP 一致
-CheckIP: true
-# 是否开启 单端登录
-SingleEnd: true
-
-# 刷新时间间隔(秒)
-#
-# 超过该时间即可触发 token 刷新、旧 token 进入容错,间隔越小安全性越高
-RefreshInterval: 300
-# 并发容错时间(秒)
-FaultTolerance: 3
-
-# 是否开启 自动续期
-#
-# 假设:单次登录有效期(7天)
-# true  只要 7天 内有操作触发刷新,登录状态就一直延续
-# false 不论 7天 内是否操作,7天 后必定要求重新登录
-AutomaticRenewal: true
-# 单次登录有效期(小时)
-AccessExpireByHour: 8

+ 0 - 73
src/gin/jwtx2/s.Login.go

@@ -1,73 +0,0 @@
-package jwtx
-
-import (
-	"errors"
-	"time"
-
-	"github.com/5-say/go-tool/gin/jwtx/db/dao/model"
-	"github.com/5-say/go-tool/gin/jwtx/db/dao/query"
-	"github.com/5-say/go-tool/gin/jwtx/tool"
-	"github.com/gin-gonic/gin"
-	"github.com/golang-jwt/jwt/v5"
-)
-
-// jwt token 登录
-//
-//	c             *gin.Context
-//	loginGroup    string       登录的 token 分组
-//	loginTerminal string       登录的 终端名称(后续登出时,若引用此处的传值为“all”,则无视配置,强制登出所有终端)
-//	accountID     uint64       登录的 账户 ID
-//
-// e.g.
-//
-//	jwtx.Singleton.Login(c, "admin", "pc", 1)
-//	jwtx.Singleton.Login(c, "admin", "mobile", 1)
-func (s *SingletonT) Login(c *gin.Context, loginGroup string, loginTerminal string, accountID uint64) (err error) {
-	// 获取分组配置
-	var (
-		config     = s.Config[loginGroup]
-		privateKey = s.PrivateKey[loginGroup]
-		q          = query.Use(s.DB[loginGroup])
-	)
-
-	// 清除旧 token
-	err = s.Logout(c, loginGroup, loginTerminal, accountID)
-	if err != nil {
-		return
-	}
-
-	var (
-		now     = time.Now()
-		expTime = now.Add(time.Hour * time.Duration(config.AccessExpireByHour))
-	)
-
-	// 创建新 token
-	token := model.JwtxToken{
-		AccountID:      accountID,
-		LoginGroup:     loginGroup,
-		LoginTerminal:  loginTerminal,
-		MakeTokenIP:    c.ClientIP(),
-		CreatedAt:      now,
-		LastRefreshAt:  now,
-		FinalRefreshAt: now,
-		ExpirationAt:   expTime,
-	}
-	if q.JwtxToken.WithContext(c).Create(&token) != nil {
-		return errors.New("create token fail")
-	}
-
-	// 构造 token 字符串
-	tokenStr, err := tool.GenerateToken(privateKey, jwt.MapClaims{
-		"iat": now.Unix(),     // 签发时间
-		"exp": expTime.Unix(), // 过期时间
-		"tid": token.ID,       // jwt token ID
-	}, tool.P_384)
-	if err != nil {
-		return errors.New("token refresh fail")
-	}
-
-	// 响应头填充 token
-	c.Writer.Header().Add("token", tokenStr)
-
-	return
-}

+ 0 - 52
src/gin/jwtx2/s.Logout.go

@@ -1,52 +0,0 @@
-package jwtx
-
-import (
-	"errors"
-
-	"github.com/5-say/go-tool/gin/jwtx/db/dao/query"
-	"github.com/5-say/go-tool/logx"
-	"github.com/gin-gonic/gin"
-)
-
-// jwt token 登出
-//
-//	c             *gin.Context
-//	loginGroup    string       登录的 token 分组
-//	loginTerminal string       登录的 终端名称(当传值为“all”时,无视配置,强制登出所有终端)
-//	accountID     uint64       登录的 账户 ID
-//
-// e.g.
-//
-//	jwtx.Singleton.Logout(c, "admin", "pc", 1)
-//	jwtx.Singleton.Logout(c, "admin", "all", 1)
-func (s *SingletonT) Logout(c *gin.Context, loginGroup string, loginTerminal string, accountID uint64) (err error) {
-	// 获取分组配置
-	var (
-		q      = query.Use(s.DB[loginGroup])
-		config = s.Config[loginGroup]
-	)
-
-	if config.SingleEnd || loginTerminal == "all" { // 强制单端登录
-
-		if _, err := q.JwtxToken.WithContext(c).Where(
-			q.JwtxToken.AccountID.Eq(accountID),
-			q.JwtxToken.LoginGroup.Eq(loginGroup),
-		).Delete(); err != nil {
-			logx.Error().Msg("强制单端登录,清除旧 token 失败 [sqlfail: " + err.Error() + "]")
-			return errors.New("clear token fail")
-		}
-
-	} else { // 多端登录
-
-		if _, err := q.JwtxToken.WithContext(c).Where(
-			q.JwtxToken.AccountID.Eq(accountID),
-			q.JwtxToken.LoginGroup.Eq(loginGroup),
-			q.JwtxToken.LoginTerminal.Eq(loginTerminal),
-		).Delete(); err != nil {
-			logx.Error().Msg("多端登录,清除旧 token 失败 [sqlfail: " + err.Error() + "]")
-			return errors.New("clear token fail")
-		}
-	}
-
-	return
-}

+ 0 - 170
src/gin/jwtx2/s.Middleware.go

@@ -1,170 +0,0 @@
-package jwtx
-
-import (
-	"context"
-	"errors"
-	"time"
-
-	"github.com/5-say/go-tool/gin/jwtx/db/dao/model"
-	"github.com/5-say/go-tool/gin/jwtx/db/dao/query"
-	"github.com/5-say/go-tool/gin/jwtx/tool"
-	"github.com/5-say/go-tool/logx"
-	"github.com/gin-gonic/gin"
-	"github.com/golang-jwt/jwt/v5"
-)
-
-// 中间件认证失败后的处理函数 ..
-var MiddlewareFailHandlerFunc = func(c *gin.Context, err error) {
-	logx.Debug().Err(err)
-	c.AbortWithStatus(401)
-}
-
-// jwtx token 中间件(token 解析、校验、刷新) ..
-//
-//	requestGroup string 请求访问的分组
-//
-// e.g.
-//
-//	jwtx.Singleton.Middleware("admin")
-//	jwtx.Singleton.Middleware("merchant")
-func (s *SingletonT) Middleware(requestGroup string) gin.HandlerFunc {
-	return func(c *gin.Context) {
-
-		// 解析 token
-		claims, err := tool.ParseToken(c.GetHeader("Authorization"), &s.PrivateKey[requestGroup].PublicKey)
-		if err != nil {
-			MiddlewareFailHandlerFunc(c, err)
-			return
-		}
-
-		// 提取 claims
-		var (
-			now    = time.Now()                      // 当前时间
-			iat, _ = claims.GetIssuedAt()            // 签发时间
-			exp, _ = claims.GetExpirationTime()      // 过期时间
-			tid    = uint64(claims["tid"].(float64)) // token ID
-		)
-
-		// token 过期时间校验
-		if exp.Unix() < now.Unix() {
-			MiddlewareFailHandlerFunc(c, errors.New("token has expired"))
-			return
-		}
-
-		// 数据库中查找 token
-		token, err := s.getDBToken(requestGroup, tid)
-		if err != nil {
-			MiddlewareFailHandlerFunc(c, err)
-			return
-		}
-
-		// 校验数据库 token 信息
-		err = s.checkDBToken(requestGroup, token, now, c.ClientIP())
-		if err != nil {
-			MiddlewareFailHandlerFunc(c, err)
-			return
-		}
-
-		// 刷新 token
-		newToken, err := s.refreshToken(requestGroup, token, now, iat)
-		if err != nil {
-			MiddlewareFailHandlerFunc(c, err)
-			return
-		}
-
-		// 将当前登录的账户信息存储上下文
-		c.Set("jwtx.accountID", token.AccountID)         // 账户 ID
-		c.Set("jwtx.loginGroup", token.LoginGroup)       // 登录的分组
-		c.Set("jwtx.loginTerminal", token.LoginTerminal) // 登录的终端
-		c.Set("jwtx.makeTokenIP", token.MakeTokenIP)     // 首次请求生成 token 的 IP 地址
-
-		// 请求前
-		c.Next()
-		// 请求后
-
-		// 响应头填充刷新后的 token
-		c.Writer.Header().Add("token", newToken)
-	}
-}
-
-// 获取数据库 token 信息
-func (s *SingletonT) getDBToken(group string, tid uint64) (token *model.JwtxToken, err error) {
-	// 查找 token
-	q := query.Use(s.DB[group])
-	o := q.JwtxToken
-	token, err = o.WithContext(context.Background()).Where(o.ID.Eq(tid)).First()
-	if err != nil {
-		return nil, err
-	}
-	return token, nil
-}
-
-// 校验数据库 token 信息
-func (s *SingletonT) checkDBToken(group string, token *model.JwtxToken, now time.Time, clientIP string) (err error) {
-	// 分组校验
-	if token.LoginGroup != group {
-		return errors.New("auth group fail")
-	}
-	// 过期时间校验
-	if token.ExpirationAt.Unix() < now.Unix() {
-		return errors.New("the token has expired")
-	}
-	// IP 一致性校验
-	if s.Config[group].CheckIP {
-		if clientIP != token.MakeTokenIP {
-			return errors.New("client ip is changed, please login again")
-		}
-	}
-	return
-}
-
-// 自动刷新 token
-func (s *SingletonT) refreshToken(group string, token *model.JwtxToken, now time.Time, iat *jwt.NumericDate) (newToken string, err error) {
-
-	var config = s.Config[group]
-
-	if iat.Unix() == token.FinalRefreshAt.Unix() { // token 未刷新
-
-		// 原始的 token 过期时间
-		expTime := token.ExpirationAt
-
-		// 需要刷新 token
-		if iat.Unix()+config.RefreshInterval < now.Unix() {
-
-			// 自动续期
-			if config.AutomaticRenewal {
-				expTime = now.Add(time.Duration(config.AccessExpireByHour) * time.Hour)
-			}
-
-			// 构造 token 字符串(过期时间不变,签发时间顺延)
-			newToken, err = tool.GenerateToken(s.PrivateKey[group], jwt.MapClaims{
-				"iat": now.Unix(),     // 签发时间
-				"exp": expTime.Unix(), // 过期时间
-				"tid": token.ID,       // jwt token ID
-			}, tool.P_384)
-			if err != nil {
-				return "", err
-			}
-
-			// 更新数据库
-			q := query.Use(s.DB[group])
-			o := q.JwtxToken
-			_, err = o.WithContext(context.Background()).Where(o.ID.Eq(token.ID)).UpdateSimple(
-				o.LastRefreshAt.Value(token.FinalRefreshAt),
-				o.FinalRefreshAt.Value(now),
-			)
-			if err != nil {
-				return "", err
-			}
-		}
-
-	} else if iat.Unix() == token.LastRefreshAt.Unix() { // token 已刷新
-
-		// 当前时间 超出 并发容错时间(不允许继续使用)
-		if now.Unix() > token.FinalRefreshAt.Unix()+config.FaultTolerance {
-			return "", errors.New("out of concurrent fault tolerance time")
-		}
-	}
-
-	return
-}

+ 0 - 18
src/gin/jwtx2/test/GenerateKey_test.go

@@ -1,18 +0,0 @@
-package test
-
-import (
-	"fmt"
-	"testing"
-
-	"github.com/5-say/go-tool/crypto/ecdsatool"
-)
-
-func Test_GenerateKey(t *testing.T) {
-	key, _ := ecdsatool.GenerateKey(ecdsatool.P_384)
-	privateKeyPEMBytes, _ := ecdsatool.PEM_EncodePrivateKey(key)
-	fmt.Println()
-	fmt.Println("密钥格式: NIST P-384")
-	fmt.Printf("\n%s\n", privateKeyPEMBytes)
-	fmt.Println("密钥格式: NIST P-384")
-	fmt.Println()
-}

+ 0 - 30
src/gin/jwtx2/test/GenerateToken_test.go

@@ -1,30 +0,0 @@
-package test
-
-import (
-	"testing"
-
-	"github.com/5-say/go-tool/gin/jwtx/tool"
-	"github.com/golang-jwt/jwt/v5"
-)
-
-func Test_GenerateToken(t *testing.T) {
-	key, err := tool.GetPrivateKey("jwtx/admin.key")
-	// key, err := ecdsatool.GenerateKey(ecdsatool.P_384)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	token, err := tool.GenerateToken(key, jwt.MapClaims{
-		"test": "demo",
-	}, tool.P_384)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	claims, err := tool.ParseToken(token, &key.PublicKey)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	t.Log(claims["test"])
-}

+ 0 - 10
src/gin/jwtx2/test/jwtx/admin.key

@@ -1,10 +0,0 @@
-密钥格式: NIST P-384
-
------BEGIN EC PRIVATE KEY-----
-MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAjnvXNxyHaw9VtbFa9
-PbnUHcWzCDTyQo7OmLCcaslC53DP2LrPDPNvgBvcpzzeNNOhZANiAASPwE1OHVHN
-BUfK9GKYvI/WTirmMRKCI7X6ga30DxJD3P9rN9tCclBR7EGmZjI9YlIpew4c4HlD
-A1AzyUA/m+FDdGYioNYc3KdwLI7SIFf3FtOubfUfReKFtN8zKgO4Kjc=
------END EC PRIVATE KEY-----
-
-密钥格式: NIST P-384

+ 0 - 24
src/gin/jwtx2/test/jwtx/admin.yaml

@@ -1,24 +0,0 @@
-
-# consult[https://gorm.io/docs/connecting_to_the_database.html]"
-MysqlDSN : "root:root@tcp(mysql:3306)/jwtx?charset=utf8mb4&parseTime=True&loc=Local"
-
-# 是否开启 IP一致性校验,当前 IP 必须与登录时 IP 一致
-CheckIP: true
-# 是否开启 单端登录
-SingleEnd: true
-
-# 刷新时间间隔(秒)
-#
-# 超过该时间即可触发 token 刷新、旧 token 进入容错,间隔越小安全性越高
-RefreshInterval: 30
-# 并发容错时间(秒)
-FaultTolerance: 3
-
-# 是否开启 自动续期
-#
-# 假设:单次登录有效期(7天)
-# true  只要 7天 内有操作触发刷新,登录状态就一直延续
-# false 不论 7天 内是否操作,7天 后必定要求重新登录
-AutomaticRenewal: true
-# 单次登录有效期(小时)
-AccessExpireByHour: 8

+ 0 - 21
src/gin/jwtx2/tool/GenerateToken.go

@@ -1,21 +0,0 @@
-package tool
-
-import (
-	"crypto/ecdsa"
-
-	"github.com/golang-jwt/jwt/v5"
-)
-
-// GenerateToken ..
-func GenerateToken(key *ecdsa.PrivateKey, claims jwt.MapClaims, cs CurveStandard) (token string, err error) {
-	switch cs {
-	case P_256:
-		return jwt.NewWithClaims(jwt.SigningMethodES256, claims).SignedString(key)
-	case P_384:
-		return jwt.NewWithClaims(jwt.SigningMethodES384, claims).SignedString(key)
-	case P_521:
-		return jwt.NewWithClaims(jwt.SigningMethodES512, claims).SignedString(key)
-	default:
-		return "", nil
-	}
-}

+ 0 - 18
src/gin/jwtx2/tool/GetPrivateKey.go

@@ -1,18 +0,0 @@
-package tool
-
-import (
-	"crypto/ecdsa"
-	"os"
-
-	"github.com/5-say/go-tool/crypto/ecdsatool"
-)
-
-// GetPrivateKey .. 从 PEM 格式文件 获取 私钥对象
-func GetPrivateKey(filePath string) (privateKey *ecdsa.PrivateKey, err error) {
-	data, err := os.ReadFile(filePath)
-	if err != nil {
-		return
-	}
-
-	return ecdsatool.PEM_DecodePrivateKey(data)
-}

+ 0 - 26
src/gin/jwtx2/tool/ParseToken.go

@@ -1,26 +0,0 @@
-package tool
-
-import (
-	"crypto/ecdsa"
-	"errors"
-
-	"github.com/golang-jwt/jwt/v5"
-)
-
-// ParseToken ..
-func ParseToken(tokenStr string, publicKey *ecdsa.PublicKey) (claims jwt.MapClaims, err error) {
-
-	jwtToken, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
-		return publicKey, nil
-	})
-	if err != nil {
-		return nil, err
-	}
-
-	claims, ok := jwtToken.Claims.(jwt.MapClaims)
-	if !ok {
-		return nil, errors.New("claims parse fail")
-	}
-
-	return
-}

+ 0 - 10
src/gin/jwtx2/tool/const.go

@@ -1,10 +0,0 @@
-package tool
-
-// 数学曲线标准
-type CurveStandard int
-
-const (
-	P_256 CurveStandard = iota + 1
-	P_384
-	P_521
-)