feat: client 增删改查
This commit is contained in:
@@ -0,0 +1,76 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/mojocn/base64Captcha"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
"sundynix-go/model/system"
|
||||||
|
systemReq "sundynix-go/model/system/request"
|
||||||
|
systemRes "sundynix-go/model/system/response"
|
||||||
|
"sundynix-go/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var store = base64Captcha.DefaultMemStore
|
||||||
|
|
||||||
|
type AuthApi struct{}
|
||||||
|
|
||||||
|
// Login api
|
||||||
|
func (a *AuthApi) Login(c *gin.Context) {
|
||||||
|
var l systemReq.Login
|
||||||
|
err := c.ShouldBindJSON(&l)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if l.CaptchaId != "" && l.Captcha != "" && store.Verify(l.CaptchaId, l.Captcha, true) {
|
||||||
|
u := &system.User{Account: l.Account, Password: l.Password}
|
||||||
|
user, err := UserService.Login(u)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("登录失败! 用户名不存在或者密码错误!", zap.Error(err))
|
||||||
|
response.FailWithMsg("用户名不存在或者密码错误", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.GetToken(c, *user)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.FailWithMsg("验证码错误", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Captcha api 生成验证码
|
||||||
|
func (u *AuthApi) Captcha(c *gin.Context) {
|
||||||
|
var driver = base64Captcha.DriverString{
|
||||||
|
Height: 80,
|
||||||
|
Width: 240,
|
||||||
|
NoiseCount: 2,
|
||||||
|
ShowLineOptions: 4,
|
||||||
|
Length: 6,
|
||||||
|
Source: "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM",
|
||||||
|
}
|
||||||
|
|
||||||
|
cp := base64Captcha.NewCaptcha(&driver, store)
|
||||||
|
id, b64s, _, err := cp.Generate()
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("GenerateCaptcha err", zap.Error(err))
|
||||||
|
response.FailWithMsg("GenerateCaptcha err", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(systemRes.CaptchaRes{
|
||||||
|
CaptchaId: id,
|
||||||
|
Captcha: b64s,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AuthApi) GetToken(c *gin.Context, user system.User) {
|
||||||
|
token, claims, err := utils.GetLoginToken(&user)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("GetToken err", zap.Error(err))
|
||||||
|
response.FailWithMsg("GetToken err", c)
|
||||||
|
}
|
||||||
|
response.OkWithData(systemRes.LoginResponse{
|
||||||
|
ExpiresAt: claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
|
||||||
|
Token: token,
|
||||||
|
User: user,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
@@ -1,6 +1,14 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
|
import "sundynix-go/service"
|
||||||
|
|
||||||
type ApiGroup struct {
|
type ApiGroup struct {
|
||||||
LoginApi
|
AuthApi
|
||||||
UserApi
|
UserApi
|
||||||
|
ClientApi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
UserService = service.ServiceGroupApp.SystemServiceGroup.UserService
|
||||||
|
ClientService = service.ServiceGroupApp.SystemServiceGroup.ClientService
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
package system
|
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
|
||||||
|
|
||||||
type LoginApi struct{}
|
|
||||||
|
|
||||||
// Login
|
|
||||||
func (u LoginApi) Login(c *gin.Context) {
|
|
||||||
c.String(200, "Hello Admin")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Captcha
|
|
||||||
func (u LoginApi) Captcha(c *gin.Context) {
|
|
||||||
c.String(200, "Hello Admin")
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/model/commom/request"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
"sundynix-go/model/system"
|
||||||
|
systemReq "sundynix-go/model/system/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClientApi struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientApi) SaveClient(c *gin.Context) {
|
||||||
|
var client system.Client
|
||||||
|
err := c.ShouldBindJSON(&client)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ClientService.SaveClient(client)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("保存客户端失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("保存客户端成功!", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientApi) UpdateClient(c *gin.Context) {
|
||||||
|
var client system.Client
|
||||||
|
err := c.ShouldBindJSON(&client)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ClientService.UpdateClient(client)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("更新客户端失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("更新客户端成功!", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientApi) GetClientList(c *gin.Context) {
|
||||||
|
var pageInfo systemReq.GetClientList
|
||||||
|
err := c.ShouldBindJSON(&pageInfo)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, total, err := ClientService.GetClientList(pageInfo)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取客户端列表失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(response.PageResult{
|
||||||
|
List: list,
|
||||||
|
Total: total,
|
||||||
|
Page: pageInfo.Current,
|
||||||
|
PageSize: pageInfo.PageSize,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientApi) Delete(c *gin.Context) {
|
||||||
|
var ids request.IdsReq
|
||||||
|
err := c.ShouldBindJSON(&ids)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ClientService.DeleteClientByIds(ids)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("删除客户端失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithMsg("删除客户端成功!", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientApi) Detail(c *gin.Context) {
|
||||||
|
var idInfo request.GetById
|
||||||
|
err := c.ShouldBindJSON(&idInfo)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client, err := ClientService.GetClientById(idInfo.ID)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取客户端详情失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(client, c)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,33 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
systemReq "sundynix-go/model/system/request"
|
||||||
|
)
|
||||||
|
|
||||||
type UserApi struct {
|
type UserApi struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserApi) GetUserList(c *gin.Context) {
|
||||||
|
var pageInfo systemReq.GetUserList
|
||||||
|
err := c.ShouldBindJSON(&pageInfo)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, total, err := UserService.GetUserList(pageInfo)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取用户列表失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(response.PageResult{
|
||||||
|
List: list,
|
||||||
|
Total: total,
|
||||||
|
Page: pageInfo.Current,
|
||||||
|
PageSize: pageInfo.PageSize,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,15 @@ system:
|
|||||||
addr: 8888
|
addr: 8888
|
||||||
db-type: mysql
|
db-type: mysql
|
||||||
router-prefix: "api"
|
router-prefix: "api"
|
||||||
|
enable-captcha: 0
|
||||||
|
|
||||||
|
jwt:
|
||||||
|
buffer-time: 1d
|
||||||
|
expires-time: 7d
|
||||||
|
issuer: sunfynix
|
||||||
|
signing-key: 9149f2eb-d517-4a50-a03a-231dbcf0d872
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mysql:
|
mysql:
|
||||||
config: charset=utf8mb4&parseTime=True&loc=Local
|
config: charset=utf8mb4&parseTime=True&loc=Local
|
||||||
|
|||||||
@@ -2,6 +2,13 @@ system:
|
|||||||
addr: 8888
|
addr: 8888
|
||||||
db-type: mysql
|
db-type: mysql
|
||||||
|
|
||||||
|
captcha:
|
||||||
|
img-height: 80
|
||||||
|
img-width: 240
|
||||||
|
key-long: 6
|
||||||
|
open-captcha: 0
|
||||||
|
open-captcha-timeout: 3600
|
||||||
|
|
||||||
mysql:
|
mysql:
|
||||||
config: charset=utf8mb4&parseTime=True&loc=Local
|
config: charset=utf8mb4&parseTime=True&loc=Local
|
||||||
db-name: sundynix_go
|
db-name: sundynix_go
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"`
|
||||||
System System `mapstructure:"system" json:"system" yaml:"system"`
|
System System `mapstructure:"system" json:"system" yaml:"system"`
|
||||||
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
|
Mysql Mysql `mapstructure:"mysql" json:"mysql" yaml:"mysql"`
|
||||||
Pgsql Pgsql `mapstructure:"pgsql" json:"pgsql" yaml:"pgsql"`
|
Pgsql Pgsql `mapstructure:"pgsql" json:"pgsql" yaml:"pgsql"`
|
||||||
|
|||||||
+4
-3
@@ -1,7 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
type System struct {
|
type System struct {
|
||||||
Addr int `mapstructure:"addr" json:"addr" yaml:"addr"`
|
Addr int `mapstructure:"addr" json:"addr" yaml:"addr"`
|
||||||
DbType string `mapstructure:"db-type" json:"db-type" yaml:"db-type"`
|
DbType string `mapstructure:"db-type" json:"db-type" yaml:"db-type"`
|
||||||
RouterPrefix string `mapstructure:"router-prefix" json:"router-prefix" yaml:"router-prefix"`
|
RouterPrefix string `mapstructure:"router-prefix" json:"router-prefix" yaml:"router-prefix"`
|
||||||
|
EnableCaptcha int `mapstructure:"enable-captcha" json:"enable-captcha" yaml:"enable-captcha"`
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -4,15 +4,17 @@ import (
|
|||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"golang.org/x/sync/singleflight"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"sundynix-go/config"
|
"sundynix-go/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 全局变量 加载在内存中
|
// 全局变量 加载在内存中
|
||||||
var (
|
var (
|
||||||
Viper *viper.Viper
|
Viper *viper.Viper
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
Config *config.Config
|
Config *config.Config
|
||||||
DB *gorm.DB
|
DB *gorm.DB
|
||||||
Redis redis.UniversalClient
|
Redis redis.UniversalClient
|
||||||
|
ConcurrencyControl = &singleflight.Group{}
|
||||||
)
|
)
|
||||||
|
|||||||
+4
-4
@@ -6,10 +6,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type BaseModel struct {
|
type BaseModel struct {
|
||||||
ID uint `gorm:"primarykey" json:"ID"` // 主键ID
|
Id uint `gorm:"primarykey" json:"id"` // 主键ID
|
||||||
CreatedAt time.Time // 创建时间
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
UpdatedAt time.Time // 更新时间
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 删除时间
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"deletedAt"` // 删除时间
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeCreate 定义一个钩子,在创建之前执行自动插入字段
|
// BeforeCreate 定义一个钩子,在创建之前执行自动插入字段
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.9.2 // indirect
|
github.com/go-sql-driver/mysql v1.9.2 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
@@ -44,6 +46,7 @@ require (
|
|||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/mojocn/base64Captcha v1.3.8 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.7.3 // indirect
|
github.com/redis/go-redis/v9 v9.7.3 // indirect
|
||||||
@@ -60,6 +63,7 @@ require (
|
|||||||
golang.org/x/arch v0.16.0 // indirect
|
golang.org/x/arch v0.16.0 // indirect
|
||||||
golang.org/x/crypto v0.37.0 // indirect
|
golang.org/x/crypto v0.37.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||||
|
golang.org/x/image v0.26.0 // indirect
|
||||||
golang.org/x/net v0.39.0 // indirect
|
golang.org/x/net v0.39.0 // indirect
|
||||||
golang.org/x/sync v0.13.0 // indirect
|
golang.org/x/sync v0.13.0 // indirect
|
||||||
golang.org/x/sys v0.32.0 // indirect
|
golang.org/x/sys v0.32.0 // indirect
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIx
|
|||||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
@@ -83,6 +87,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/mojocn/base64Captcha v1.3.8 h1:rrN9BhCwXKS8ht1e21kvR3iTaMgf4qPC9sRoV52bqEg=
|
||||||
|
github.com/mojocn/base64Captcha v1.3.8/go.mod h1:QFZy927L8HVP3+VV5z2b1EAEiv1KxVJKZbAucVgLUy4=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||||
@@ -125,6 +131,7 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
@@ -133,23 +140,85 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
|||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||||
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||||
|
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
||||||
|
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
|
||||||
|
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
||||||
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ func MigrateTable() {
|
|||||||
db := global.DB
|
db := global.DB
|
||||||
err := db.AutoMigrate(
|
err := db.AutoMigrate(
|
||||||
system.User{},
|
system.User{},
|
||||||
|
system.Client{},
|
||||||
|
system.SysOperationRecord{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
global.Logger.Error("Migrate table failed,err:", zap.Error(err))
|
global.Logger.Error("Migrate table failed,err:", zap.Error(err))
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/middleware"
|
||||||
"sundynix-go/router"
|
"sundynix-go/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,15 +25,16 @@ func Routers() {
|
|||||||
PublicGroup := Router.Group(global.Config.System.RouterPrefix)
|
PublicGroup := Router.Group(global.Config.System.RouterPrefix)
|
||||||
|
|
||||||
//鉴权中间件
|
//鉴权中间件
|
||||||
//NeedAuthGroup.Use(middleware.JWTAuthMiddleware())
|
NeedAuthGroup.Use(middleware.AuthMiddleware())
|
||||||
{
|
{
|
||||||
//无须鉴权的路由
|
//无须鉴权的路由
|
||||||
systemRouter.InitLoginRouter(PublicGroup) //登录和验证码不需要鉴权
|
systemRouter.InitAuthRouter(PublicGroup) //登录和验证码不需要鉴权
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
//需要鉴权的路由
|
//需要鉴权的路由
|
||||||
systemRouter.InitUserRouter(NeedAuthGroup)
|
systemRouter.InitUserRouter(NeedAuthGroup) //用户相关
|
||||||
|
systemRouter.InitClientRouter(NeedAuthGroup) //客户端相关
|
||||||
}
|
}
|
||||||
|
|
||||||
address := fmt.Sprintf(":%d", global.Config.System.Addr)
|
address := fmt.Sprintf(":%d", global.Config.System.Addr)
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"sundynix-go/model/commom/response"
|
||||||
|
"sundynix-go/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthMiddleware 验证token有效性
|
||||||
|
func AuthMiddleware() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
token := utils.GetToken(c)
|
||||||
|
if token == "" {
|
||||||
|
response.NoAuth("未登录或非法访问", c)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//todo 黑名单处理
|
||||||
|
|
||||||
|
j := utils.NewJWT()
|
||||||
|
// 解析token信息
|
||||||
|
claims, err := j.ParseToken(token)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, utils.TokenExpired) {
|
||||||
|
response.NoAuth("登录过期", c)
|
||||||
|
utils.ClearToken(c)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.NoAuth(err.Error(), c)
|
||||||
|
utils.ClearToken(c)
|
||||||
|
c.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Set("claims", claims)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PageInfo Paging common input parameter structure
|
||||||
|
type PageInfo struct {
|
||||||
|
Current int `json:"current" form:"current"` // 页码
|
||||||
|
PageSize int `json:"pageSize" form:"pageSize"` // 每页大小
|
||||||
|
Keyword string `json:"keyword" form:"keyword"` // 关键字
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PageInfo) Paginate() func(db *gorm.DB) *gorm.DB {
|
||||||
|
return func(db *gorm.DB) *gorm.DB {
|
||||||
|
if r.Current <= 0 {
|
||||||
|
r.Current = 1
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case r.PageSize > 100:
|
||||||
|
r.PageSize = 100
|
||||||
|
case r.PageSize <= 0:
|
||||||
|
r.PageSize = 10
|
||||||
|
}
|
||||||
|
offset := (r.Current - 1) * r.PageSize
|
||||||
|
return db.Offset(offset).Limit(r.PageSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetById Find by id structure
|
||||||
|
type GetById struct {
|
||||||
|
ID int `json:"id" form:"id"` // 主键ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GetById) Uint() uint {
|
||||||
|
return uint(r.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
type IdsReq struct {
|
||||||
|
Ids []int `json:"ids" form:"ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAuthorityId Get role by id structure
|
||||||
|
type GetAuthorityId struct {
|
||||||
|
AuthorityId uint `json:"authorityId" form:"authorityId"` // 角色ID
|
||||||
|
}
|
||||||
|
|
||||||
|
type Empty struct{}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
type PageResult struct {
|
||||||
|
List interface{} `json:"list"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"pageSize"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SUCCESS = 200
|
||||||
|
ERROR = 7
|
||||||
|
)
|
||||||
|
|
||||||
|
// Result 返回结果
|
||||||
|
func Result(code int, data interface{}, msg string, c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, Response{
|
||||||
|
code,
|
||||||
|
data,
|
||||||
|
msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok 成功返回
|
||||||
|
func Ok(c *gin.Context) {
|
||||||
|
Result(SUCCESS, map[string]interface{}{}, "操作成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OkWithData 带数据成功返回
|
||||||
|
func OkWithData(data interface{}, c *gin.Context) {
|
||||||
|
Result(SUCCESS, data, "操作成功", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OkWithMsg 带信息成功返回
|
||||||
|
func OkWithMsg(msg string, c *gin.Context) {
|
||||||
|
Result(SUCCESS, map[string]interface{}{}, msg, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail 失败返回
|
||||||
|
func Fail(code int, msg string, c *gin.Context) {
|
||||||
|
Result(code, map[string]interface{}{}, "操作失败", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FailWithMsg 带信息失败返回
|
||||||
|
func FailWithMsg(msg string, c *gin.Context) {
|
||||||
|
Result(ERROR, map[string]interface{}{}, msg, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NoAuth 未授权返回
|
||||||
|
func NoAuth(message string, c *gin.Context) {
|
||||||
|
c.JSON(http.StatusUnauthorized, Response{
|
||||||
|
7,
|
||||||
|
nil,
|
||||||
|
message,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import "github.com/mojocn/base64Captcha"
|
||||||
|
|
||||||
|
// configJsonBody json request body.
|
||||||
|
type CaptchaReqBody struct {
|
||||||
|
Id string
|
||||||
|
CaptchaType string
|
||||||
|
VerifyValue string
|
||||||
|
DriverAudio *base64Captcha.DriverAudio
|
||||||
|
DriverString *base64Captcha.DriverString
|
||||||
|
DriverChinese *base64Captcha.DriverChinese
|
||||||
|
DriverMath *base64Captcha.DriverMath
|
||||||
|
DriverDigit *base64Captcha.DriverDigit
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import common "sundynix-go/model/commom/request"
|
||||||
|
|
||||||
|
type GetClientList struct {
|
||||||
|
common.PageInfo
|
||||||
|
ClientId string `json:"clientId" form:"clientId"`
|
||||||
|
Name string `json:"name" form:"name"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import common "sundynix-go/model/commom/request"
|
||||||
|
|
||||||
|
type Login struct {
|
||||||
|
Account string `json:"account"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Captcha string `json:"captcha"`
|
||||||
|
CaptchaId string `json:"captchaId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetUserList struct {
|
||||||
|
common.PageInfo
|
||||||
|
Account string `json:"account" form:"account"`
|
||||||
|
Phone string `json:"phone" form:"phone"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
type CaptchaRes struct {
|
||||||
|
CaptchaId string `json:"captchaId"`
|
||||||
|
Captcha string `json:"captcha"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "sundynix-go/model/system"
|
||||||
|
|
||||||
|
type SysUserResponse struct {
|
||||||
|
User system.User `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginResponse struct {
|
||||||
|
User system.User `json:"user"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
ExpiresAt int64 `json:"expiresAt"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import "sundynix-go/global"
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
global.BaseModel
|
||||||
|
ClientId string `gorm:"size:20;" json:"clientId"`
|
||||||
|
Name string `gorm:"size:50;" json:"name"`
|
||||||
|
GrantType string `gorm:"size:50;" json:"grantType"`
|
||||||
|
AdditionalInfo string `gorm:"type:text" json:"additionalInfo"`
|
||||||
|
ActiveTimeout uint `json:"activeTimeout"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SysOperationRecord struct {
|
||||||
|
global.BaseModel
|
||||||
|
Ip string `json:"ip" form:"ip" gorm:"column:ip;comment:请求ip"` // 请求ip
|
||||||
|
Method string `json:"method" form:"method" gorm:"column:method;comment:请求方法"` // 请求方法
|
||||||
|
Path string `json:"path" form:"path" gorm:"column:path;comment:请求路径"` // 请求路径
|
||||||
|
Status int `json:"status" form:"status" gorm:"column:status;comment:请求状态"` // 请求状态
|
||||||
|
Latency time.Duration `json:"latency" form:"latency" gorm:"column:latency;comment:延迟" swaggertype:"string"` // 延迟
|
||||||
|
Agent string `json:"agent" form:"agent" gorm:"type:text;column:agent;comment:代理"` // 代理
|
||||||
|
ErrorMessage string `json:"error_message" form:"error_message" gorm:"column:error_message;comment:错误信息"` // 错误信息
|
||||||
|
Body string `json:"body" form:"body" gorm:"type:text;column:body;comment:请求Body"` // 请求Body
|
||||||
|
Resp string `json:"resp" form:"resp" gorm:"type:text;column:resp;comment:响应Body"` // 响应Body
|
||||||
|
UserID int `json:"user_id" form:"user_id" gorm:"column:user_id;comment:用户id"` // 用户id
|
||||||
|
User User `json:"user"`
|
||||||
|
}
|
||||||
@@ -1,7 +1,14 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import "sundynix-go/global"
|
import (
|
||||||
|
"sundynix-go/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Login interface {
|
||||||
|
GetAccount() string
|
||||||
|
GetUserId() uint
|
||||||
|
GetUserInfo() any
|
||||||
|
}
|
||||||
type User struct {
|
type User struct {
|
||||||
global.BaseModel
|
global.BaseModel
|
||||||
ClientId string `gorm:"size:20;" json:"clientId"`
|
ClientId string `gorm:"size:20;" json:"clientId"`
|
||||||
@@ -9,3 +16,14 @@ type User struct {
|
|||||||
Password string `gorm:"size:100;" json:"-" form:"password"`
|
Password string `gorm:"size:100;" json:"-" form:"password"`
|
||||||
Phone string `gorm:"size:11;" json:"phone" form:"phone"`
|
Phone string `gorm:"size:11;" json:"phone" form:"phone"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) GetAccount() string {
|
||||||
|
return u.Account
|
||||||
|
}
|
||||||
|
func (u *User) GetUserId() uint {
|
||||||
|
return u.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetUserInfo() any {
|
||||||
|
return *u
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthRouter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitAuthRouter 初始化登录路由
|
||||||
|
func (s *AuthRouter) InitAuthRouter(Router *gin.RouterGroup) {
|
||||||
|
loginRouter := Router.Group("auth")
|
||||||
|
{
|
||||||
|
loginRouter.POST("login", authApi.Login)
|
||||||
|
loginRouter.GET("captcha", authApi.Captcha)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
type ClientRouter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientRouter) InitClientRouter(Router *gin.RouterGroup) {
|
||||||
|
clientRouter := Router.Group("client")
|
||||||
|
{
|
||||||
|
clientRouter.POST("save", clientApi.SaveClient)
|
||||||
|
clientRouter.POST("update", clientApi.UpdateClient)
|
||||||
|
clientRouter.POST("getClientList", clientApi.GetClientList)
|
||||||
|
clientRouter.GET("delete", clientApi.Delete)
|
||||||
|
clientRouter.GET("detail", clientApi.Detail)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,12 +3,14 @@ package system
|
|||||||
import v1 "sundynix-go/api/v1"
|
import v1 "sundynix-go/api/v1"
|
||||||
|
|
||||||
type RouterGroup struct {
|
type RouterGroup struct {
|
||||||
LoginRouter
|
AuthRouter
|
||||||
UserRouter
|
UserRouter
|
||||||
|
ClientRouter
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化路由
|
// 初始化路由
|
||||||
var (
|
var (
|
||||||
loginApi = v1.ApiGroupApp.SystemApiGroup.LoginApi
|
authApi = v1.ApiGroupApp.SystemApiGroup.AuthApi
|
||||||
userApi = v1.ApiGroupApp.SystemApiGroup.UserApi
|
userApi = v1.ApiGroupApp.SystemApiGroup.UserApi
|
||||||
|
clientApi = v1.ApiGroupApp.SystemApiGroup.ClientApi
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LoginRouter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitLoginRouter 初始化登录路由
|
|
||||||
func (s *LoginRouter) InitLoginRouter(Router *gin.RouterGroup) {
|
|
||||||
loginRouter := Router.Group("login")
|
|
||||||
{
|
|
||||||
loginRouter.POST("login", loginApi.Login)
|
|
||||||
loginRouter.POST("captcha", loginApi.Captcha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,4 +8,8 @@ type UserRouter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) {
|
func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup) {
|
||||||
|
userRouter := Router.Group("user")
|
||||||
|
{
|
||||||
|
userRouter.POST("getUserList", userApi.GetUserList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import "sundynix-go/service/system"
|
||||||
|
|
||||||
|
var ServiceGroupApp = new(ServiceGroup)
|
||||||
|
|
||||||
|
type ServiceGroup struct {
|
||||||
|
SystemServiceGroup system.ServiceGroup
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
type ServiceGroup struct {
|
||||||
|
UserService
|
||||||
|
ClientService
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"sundynix-go/global"
|
||||||
|
common "sundynix-go/model/commom/request"
|
||||||
|
"sundynix-go/model/system"
|
||||||
|
systemReq "sundynix-go/model/system/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClientService struct{}
|
||||||
|
|
||||||
|
var ClientServiceApp = new(ClientService)
|
||||||
|
|
||||||
|
func (s *ClientService) SaveClient(client system.Client) error {
|
||||||
|
if !errors.Is(global.DB.Where("client_id = ?", client.ClientId).First(&system.Client{}).Error, gorm.ErrRecordNotFound) {
|
||||||
|
return errors.New("存在重复clientId,请修改clientId")
|
||||||
|
}
|
||||||
|
return global.DB.Create(&client).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientService) UpdateClient(client system.Client) error {
|
||||||
|
return global.DB.Model(&client).Where("id = ?", client.Id).Updates(&client).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientService) GetClientList(info systemReq.GetClientList) (list interface{}, total int64, err error) {
|
||||||
|
limit := info.PageSize
|
||||||
|
offset := info.PageSize * (info.Current - 1)
|
||||||
|
db := global.DB.Model(&system.Client{})
|
||||||
|
var clientList []system.Client
|
||||||
|
if info.ClientId != "" {
|
||||||
|
db = db.Where("client_id = ?", info.ClientId)
|
||||||
|
}
|
||||||
|
if info.Name != "" {
|
||||||
|
db = db.Where("name LIKE ?", "%"+info.Name+"%")
|
||||||
|
}
|
||||||
|
err = db.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.Limit(limit).Offset(offset).Find(&clientList).Error
|
||||||
|
return clientList, total, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientService) DeleteClientByIds(ids common.IdsReq) (err error) {
|
||||||
|
return global.DB.Delete(&system.Client{}, "id IN ?", ids.Ids).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientService) GetClientById(id int) (client system.Client, err error) {
|
||||||
|
err = global.DB.Where("id = ?", id).First(&client).Error
|
||||||
|
return client, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"sundynix-go/global"
|
||||||
|
"sundynix-go/model/system"
|
||||||
|
systemReq "sundynix-go/model/system/request"
|
||||||
|
"sundynix-go/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserService struct{}
|
||||||
|
|
||||||
|
var UserServiceApp = new(UserService)
|
||||||
|
|
||||||
|
func (userService *UserService) Login(u *system.User) (userInfo *system.User, err error) {
|
||||||
|
var user system.User
|
||||||
|
err = global.DB.Where("account = ?", u.Account).First(&user).Error
|
||||||
|
if err == nil {
|
||||||
|
if ok := utils.BcryptCheck(u.Password, user.Password); !ok {
|
||||||
|
return nil, errors.New("密码错误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (userService *UserService) GetUserList(info systemReq.GetUserList) (list interface{}, total int64, err error) {
|
||||||
|
limit := info.PageSize
|
||||||
|
offset := info.PageSize * (info.Current - 1)
|
||||||
|
db := global.DB.Model(&system.User{})
|
||||||
|
var userList []system.User
|
||||||
|
|
||||||
|
if info.Account != "" {
|
||||||
|
db = db.Where("account LIKE ?", "%"+info.Account+"%")
|
||||||
|
}
|
||||||
|
if info.Phone != "" {
|
||||||
|
db = db.Where("phone LIKE ?", "%"+info.Phone+"%")
|
||||||
|
}
|
||||||
|
err = db.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = db.Limit(limit).Offset(offset).Find(&userList).Error
|
||||||
|
return userList, total, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package captcha
|
||||||
|
|
||||||
|
import "github.com/mojocn/base64Captcha"
|
||||||
|
|
||||||
|
var CaptchaStore = base64Captcha.DefaultMemStore
|
||||||
@@ -78,6 +78,19 @@ func GetToken(c *gin.Context) string {
|
|||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearToken 清除Cookie中的token
|
||||||
|
func ClearToken(c *gin.Context) {
|
||||||
|
host, _, err := net.SplitHostPort(c.Request.Host)
|
||||||
|
if err != nil {
|
||||||
|
host = c.Request.Host
|
||||||
|
}
|
||||||
|
if net.ParseIP(host) != nil {
|
||||||
|
c.SetCookie("x-token", "", -1, "/", "", false, false)
|
||||||
|
} else {
|
||||||
|
c.SetCookie("x-token", "", -1, "/", host, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserInfo 从 gin.Context 中获取用户信息,并返回 CustomClaims 类型的指针。
|
// GetUserInfo 从 gin.Context 中获取用户信息,并返回 CustomClaims 类型的指针。
|
||||||
// 该函数首先尝试从上下文中获取已存在的 claims,如果不存在,则调用 GetClaims 函数获取 claims。
|
// 该函数首先尝试从上下文中获取已存在的 claims,如果不存在,则调用 GetClaims 函数获取 claims。
|
||||||
// 如果获取 claims 失败,则返回 nil。
|
// 如果获取 claims 失败,则返回 nil。
|
||||||
|
|||||||
+5
-5
@@ -1,14 +1,14 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHashPwd(t *testing.T) {
|
func TestHashPwd(t *testing.T) {
|
||||||
hash := BcryptHash("admin")
|
//hash := BcryptHash("admin")
|
||||||
fmt.Println(hash) // $2a$10$QC/zkQ/ohPmvjF/goDyicu7cHgAEj8gHg6OTDHWhbYQMHHn4dwxX2
|
//fmt.Println(hash) // $2a$10$QC/zkQ/ohPmvjF/goDyicu7cHgAEj8gHg6OTDHWhbYQMHHn4dwxX2
|
||||||
|
//
|
||||||
|
//check := BcryptCheck("admin", "$2a$10$QC/zkQ/ohPmvjF/goDyicu7cHgAEj8gHg6OTDHWhbYQMHHn4dwxX2")
|
||||||
|
//fmt.Println(check)
|
||||||
|
|
||||||
check := BcryptCheck("admin", "$2a$10$QC/zkQ/ohPmvjF/goDyicu7cHgAEj8gHg6OTDHWhbYQMHHn4dwxX2")
|
|
||||||
fmt.Println(check)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseDuration 解析时间
|
||||||
|
func ParseDuration(d string) (time.Duration, error) {
|
||||||
|
d = strings.TrimSpace(d)
|
||||||
|
dr, err := time.ParseDuration(d)
|
||||||
|
if err == nil {
|
||||||
|
return dr, nil
|
||||||
|
}
|
||||||
|
if strings.Contains(d, "d") {
|
||||||
|
index := strings.Index(d, "d")
|
||||||
|
|
||||||
|
hour, _ := strconv.Atoi(d[:index])
|
||||||
|
dr = time.Hour * 24 * time.Duration(hour)
|
||||||
|
ndr, err := time.ParseDuration(d[index+1:])
|
||||||
|
if err != nil {
|
||||||
|
return dr, nil
|
||||||
|
}
|
||||||
|
return dr + ndr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dv, err := strconv.ParseInt(d, 10, 64)
|
||||||
|
return time.Duration(dv), err
|
||||||
|
}
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Rules map[string][]string
|
||||||
|
|
||||||
|
type RulesMap map[string]Rules
|
||||||
|
|
||||||
|
var CustomizeMap = make(map[string]Rules)
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: RegisterRule
|
||||||
|
//@description: 注册自定义规则方案建议在路由初始化层即注册
|
||||||
|
//@param: key string, rule Rules
|
||||||
|
//@return: err error
|
||||||
|
|
||||||
|
func RegisterRule(key string, rule Rules) (err error) {
|
||||||
|
if CustomizeMap[key] != nil {
|
||||||
|
return errors.New(key + "已注册,无法重复注册")
|
||||||
|
} else {
|
||||||
|
CustomizeMap[key] = rule
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: NotEmpty
|
||||||
|
//@description: 非空 不能为其对应类型的0值
|
||||||
|
//@return: string
|
||||||
|
|
||||||
|
func NotEmpty() string {
|
||||||
|
return "notEmpty"
|
||||||
|
}
|
||||||
|
|
||||||
|
// @author: [zooqkl](https://github.com/zooqkl)
|
||||||
|
// @function: RegexpMatch
|
||||||
|
// @description: 正则校验 校验输入项是否满足正则表达式
|
||||||
|
// @param: rule string
|
||||||
|
// @return: string
|
||||||
|
|
||||||
|
func RegexpMatch(rule string) string {
|
||||||
|
return "regexp=" + rule
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: Lt
|
||||||
|
//@description: 小于入参(<) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
|
||||||
|
//@param: mark string
|
||||||
|
//@return: string
|
||||||
|
|
||||||
|
func Lt(mark string) string {
|
||||||
|
return "lt=" + mark
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: Le
|
||||||
|
//@description: 小于等于入参(<=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
|
||||||
|
//@param: mark string
|
||||||
|
//@return: string
|
||||||
|
|
||||||
|
func Le(mark string) string {
|
||||||
|
return "le=" + mark
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: Eq
|
||||||
|
//@description: 等于入参(==) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
|
||||||
|
//@param: mark string
|
||||||
|
//@return: string
|
||||||
|
|
||||||
|
func Eq(mark string) string {
|
||||||
|
return "eq=" + mark
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: Ne
|
||||||
|
//@description: 不等于入参(!=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
|
||||||
|
//@param: mark string
|
||||||
|
//@return: string
|
||||||
|
|
||||||
|
func Ne(mark string) string {
|
||||||
|
return "ne=" + mark
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: Ge
|
||||||
|
//@description: 大于等于入参(>=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
|
||||||
|
//@param: mark string
|
||||||
|
//@return: string
|
||||||
|
|
||||||
|
func Ge(mark string) string {
|
||||||
|
return "ge=" + mark
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: Gt
|
||||||
|
//@description: 大于入参(>) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
|
||||||
|
//@param: mark string
|
||||||
|
//@return: string
|
||||||
|
|
||||||
|
func Gt(mark string) string {
|
||||||
|
return "gt=" + mark
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: Verify
|
||||||
|
//@description: 校验方法
|
||||||
|
//@param: st interface{}, roleMap Rules(入参实例,规则map)
|
||||||
|
//@return: err error
|
||||||
|
|
||||||
|
func Verify(st interface{}, roleMap Rules) (err error) {
|
||||||
|
compareMap := map[string]bool{
|
||||||
|
"lt": true,
|
||||||
|
"le": true,
|
||||||
|
"eq": true,
|
||||||
|
"ne": true,
|
||||||
|
"ge": true,
|
||||||
|
"gt": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := reflect.TypeOf(st)
|
||||||
|
val := reflect.ValueOf(st) // 获取reflect.Type类型
|
||||||
|
|
||||||
|
kd := val.Kind() // 获取到st对应的类别
|
||||||
|
if kd != reflect.Struct {
|
||||||
|
return errors.New("expect struct")
|
||||||
|
}
|
||||||
|
num := val.NumField()
|
||||||
|
// 遍历结构体的所有字段
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
tagVal := typ.Field(i)
|
||||||
|
val := val.Field(i)
|
||||||
|
if tagVal.Type.Kind() == reflect.Struct {
|
||||||
|
if err = Verify(val.Interface(), roleMap); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(roleMap[tagVal.Name]) > 0 {
|
||||||
|
for _, v := range roleMap[tagVal.Name] {
|
||||||
|
switch {
|
||||||
|
case v == "notEmpty":
|
||||||
|
if isBlank(val) {
|
||||||
|
return errors.New(tagVal.Name + "值不能为空")
|
||||||
|
}
|
||||||
|
case strings.Split(v, "=")[0] == "regexp":
|
||||||
|
if !regexpMatch(strings.Split(v, "=")[1], val.String()) {
|
||||||
|
return errors.New(tagVal.Name + "格式校验不通过")
|
||||||
|
}
|
||||||
|
case compareMap[strings.Split(v, "=")[0]]:
|
||||||
|
if !compareVerify(val, v) {
|
||||||
|
return errors.New(tagVal.Name + "长度或值不在合法范围," + v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: compareVerify
|
||||||
|
//@description: 长度和数字的校验方法 根据类型自动校验
|
||||||
|
//@param: value reflect.Value, VerifyStr string
|
||||||
|
//@return: bool
|
||||||
|
|
||||||
|
func compareVerify(value reflect.Value, VerifyStr string) bool {
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
return compare(len([]rune(value.String())), VerifyStr)
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
return compare(value.Len(), VerifyStr)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return compare(value.Uint(), VerifyStr)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return compare(value.Float(), VerifyStr)
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return compare(value.Int(), VerifyStr)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: isBlank
|
||||||
|
//@description: 非空校验
|
||||||
|
//@param: value reflect.Value
|
||||||
|
//@return: bool
|
||||||
|
|
||||||
|
func isBlank(value reflect.Value) bool {
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.String, reflect.Slice:
|
||||||
|
return value.Len() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !value.Bool()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return value.Int() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return value.Uint() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return value.Float() == 0
|
||||||
|
case reflect.Interface, reflect.Ptr:
|
||||||
|
return value.IsNil()
|
||||||
|
}
|
||||||
|
return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
//@author: [piexlmax](https://github.com/piexlmax)
|
||||||
|
//@function: compare
|
||||||
|
//@description: 比较函数
|
||||||
|
//@param: value interface{}, VerifyStr string
|
||||||
|
//@return: bool
|
||||||
|
|
||||||
|
func compare(value interface{}, VerifyStr string) bool {
|
||||||
|
VerifyStrArr := strings.Split(VerifyStr, "=")
|
||||||
|
val := reflect.ValueOf(value)
|
||||||
|
switch val.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
VInt, VErr := strconv.ParseInt(VerifyStrArr[1], 10, 64)
|
||||||
|
if VErr != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case VerifyStrArr[0] == "lt":
|
||||||
|
return val.Int() < VInt
|
||||||
|
case VerifyStrArr[0] == "le":
|
||||||
|
return val.Int() <= VInt
|
||||||
|
case VerifyStrArr[0] == "eq":
|
||||||
|
return val.Int() == VInt
|
||||||
|
case VerifyStrArr[0] == "ne":
|
||||||
|
return val.Int() != VInt
|
||||||
|
case VerifyStrArr[0] == "ge":
|
||||||
|
return val.Int() >= VInt
|
||||||
|
case VerifyStrArr[0] == "gt":
|
||||||
|
return val.Int() > VInt
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
VInt, VErr := strconv.Atoi(VerifyStrArr[1])
|
||||||
|
if VErr != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case VerifyStrArr[0] == "lt":
|
||||||
|
return val.Uint() < uint64(VInt)
|
||||||
|
case VerifyStrArr[0] == "le":
|
||||||
|
return val.Uint() <= uint64(VInt)
|
||||||
|
case VerifyStrArr[0] == "eq":
|
||||||
|
return val.Uint() == uint64(VInt)
|
||||||
|
case VerifyStrArr[0] == "ne":
|
||||||
|
return val.Uint() != uint64(VInt)
|
||||||
|
case VerifyStrArr[0] == "ge":
|
||||||
|
return val.Uint() >= uint64(VInt)
|
||||||
|
case VerifyStrArr[0] == "gt":
|
||||||
|
return val.Uint() > uint64(VInt)
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
VFloat, VErr := strconv.ParseFloat(VerifyStrArr[1], 64)
|
||||||
|
if VErr != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case VerifyStrArr[0] == "lt":
|
||||||
|
return val.Float() < VFloat
|
||||||
|
case VerifyStrArr[0] == "le":
|
||||||
|
return val.Float() <= VFloat
|
||||||
|
case VerifyStrArr[0] == "eq":
|
||||||
|
return val.Float() == VFloat
|
||||||
|
case VerifyStrArr[0] == "ne":
|
||||||
|
return val.Float() != VFloat
|
||||||
|
case VerifyStrArr[0] == "ge":
|
||||||
|
return val.Float() >= VFloat
|
||||||
|
case VerifyStrArr[0] == "gt":
|
||||||
|
return val.Float() > VFloat
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func regexpMatch(rule, matchStr string) bool {
|
||||||
|
return regexp.MustCompile(rule).MatchString(matchStr)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user