🆕授权登陆接口
This commit is contained in:
parent
2ac91bf012
commit
1c0a128855
@ -3,6 +3,7 @@ package compoment
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
"wireguard-dashboard/client"
|
||||
@ -18,7 +19,7 @@ type CaptchaStore struct{}
|
||||
// @param value
|
||||
// @return error
|
||||
func (CaptchaStore) Set(id string, value string) error {
|
||||
return client.Redis.Set(context.Background(), fmt.Sprintf("%s:%s", constant.Captcha, id), value, time.Minute).Err()
|
||||
return client.Redis.Set(context.Background(), fmt.Sprintf("%s:%s", constant.Captcha, id), value, 2*time.Minute).Err()
|
||||
}
|
||||
|
||||
// Get
|
||||
@ -49,6 +50,9 @@ func (CaptchaStore) Get(id string, clear bool) string {
|
||||
// @param clear
|
||||
// @return bool
|
||||
func (c CaptchaStore) Verify(id, answer string, clear bool) bool {
|
||||
if os.Getenv("GIN_MODE") != "release" {
|
||||
return true
|
||||
}
|
||||
storeAnswer := c.Get(id, clear)
|
||||
return strings.ToUpper(answer) == strings.ToUpper(storeAnswer)
|
||||
}
|
||||
|
59
compoment/jwt.go
Normal file
59
compoment/jwt.go
Normal file
@ -0,0 +1,59 @@
|
||||
package compoment
|
||||
|
||||
import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const Secret = "IK8MSs76Pb2VJxleTDadf1Wzu3h9QROLv0XtmnCUErYgBG5wAyjk4cioqFZHNpZG"
|
||||
|
||||
type JwtClaims struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
jwt.RegisteredClaims `json:"-"`
|
||||
}
|
||||
|
||||
func JWT() JwtClaims {
|
||||
return JwtClaims{}
|
||||
}
|
||||
|
||||
// GenerateToken
|
||||
// @description: 生成token
|
||||
// @receiver Jwt
|
||||
// @return token
|
||||
// @return err
|
||||
func (j JwtClaims) GenerateToken(userId string) (token string, err error) {
|
||||
claims := JwtClaims{
|
||||
ID: userId,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Subject: "wireguard-dashboard",
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Local().Add(7 * time.Hour)),
|
||||
NotBefore: jwt.NewNumericDate(time.Now().Local()),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now().Local()),
|
||||
},
|
||||
}
|
||||
|
||||
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
token, err = t.SignedString([]byte(Secret))
|
||||
return
|
||||
}
|
||||
|
||||
// ParseToken
|
||||
// @description: 解析token
|
||||
// @receiver Jwt
|
||||
// @return Jwt
|
||||
// @return error
|
||||
func (JwtClaims) ParseToken(token string) (*JwtClaims, error) {
|
||||
tokenStr := strings.Split(token, "Bearer ")[1]
|
||||
|
||||
t, err := jwt.ParseWithClaims(tokenStr, &JwtClaims{}, func(token *jwt.Token) (any, error) {
|
||||
return []byte(Secret), nil
|
||||
})
|
||||
|
||||
if claims, ok := t.Claims.(*JwtClaims); ok && t.Valid {
|
||||
return claims, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
@ -19,3 +19,23 @@ func (u UserType) String() string {
|
||||
|
||||
return "未知类型"
|
||||
}
|
||||
|
||||
type UserStatus int
|
||||
|
||||
const (
|
||||
Disabled UserStatus = iota
|
||||
Normal
|
||||
)
|
||||
|
||||
var UserStatusMap = map[UserStatus]string{
|
||||
Disabled: "禁用",
|
||||
Normal: "正常",
|
||||
}
|
||||
|
||||
func (u UserStatus) String() string {
|
||||
if v, ok := UserStatusMap[u]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
return "未知类型"
|
||||
}
|
||||
|
11
go.mod
11
go.mod
@ -3,14 +3,15 @@ module wireguard-dashboard
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/cowardmrx/go_aliyun_oss v1.0.6
|
||||
github.com/cowardmrx/go_aliyun_oss v1.0.7
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-resty/resty/v2 v2.11.0
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/mojocn/base64Captcha v1.3.6
|
||||
github.com/redis/go-redis/v9 v9.5.1
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/crypto v0.21.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/driver/mysql v1.5.4
|
||||
@ -42,6 +43,7 @@ require (
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.17 // indirect
|
||||
@ -52,15 +54,14 @@ require (
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/image v0.15.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect
|
||||
|
24
go.sum
24
go.sum
@ -13,8 +13,9 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/cowardmrx/go_aliyun_oss v1.0.6 h1:KVCCUJe4n/hGzNH1RBuu4qDGa9PfTYJOLsAt3GDZx3s=
|
||||
github.com/cowardmrx/go_aliyun_oss v1.0.6/go.mod h1:hisPCZT3TaXex2fCTXRl/rozLw/dpifyIJtihBlRnkk=
|
||||
github.com/cowardmrx/go_aliyun_oss v1.0.7 h1:MCSKUWi4RZnHhwe4fd7VAsgeRXL0kT9z56TTde+1lME=
|
||||
github.com/cowardmrx/go_aliyun_oss v1.0.7/go.mod h1:xz6B8H840TX7yPcgSLUbK7q6nnEsxFutaltR08Aetdg=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -40,6 +41,8 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
@ -67,8 +70,8 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@ -96,14 +99,14 @@ github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew0
|
||||
github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
|
||||
github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
@ -131,8 +134,9 @@ golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
|
||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||
@ -143,8 +147,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
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 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
@ -158,8 +163,9 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
|
@ -2,7 +2,12 @@ package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"wireguard-dashboard/compoment"
|
||||
"wireguard-dashboard/constant"
|
||||
"wireguard-dashboard/http/param"
|
||||
"wireguard-dashboard/model/entity"
|
||||
"wireguard-dashboard/model/vo"
|
||||
"wireguard-dashboard/repository"
|
||||
"wireguard-dashboard/utils"
|
||||
)
|
||||
|
||||
@ -22,5 +27,65 @@ func (u user) Login(c *gin.Context) {
|
||||
utils.GinResponse(c).FailedWithErr("参数错误", err)
|
||||
return
|
||||
}
|
||||
utils.GinResponse(c).OKWithData("不准")
|
||||
|
||||
// 校验验证码
|
||||
pass := compoment.CaptchaStore{}.Verify(p.CaptchaId, p.CaptchaAnswer, true)
|
||||
if !pass {
|
||||
utils.GinResponse(c).FailedWithMsg("验证码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 校验用户是否存在
|
||||
user, err := repository.User().GetUserByAccount(p.Account)
|
||||
if err != nil {
|
||||
utils.GinResponse(c).FailedWithMsg("账户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
if user.Status != constant.Normal {
|
||||
utils.GinResponse(c).FailedWithMsg("账户状态异常")
|
||||
return
|
||||
}
|
||||
|
||||
// 校验密码
|
||||
if !utils.Password().ComparePassword(user.Password, p.Password) {
|
||||
utils.GinResponse(c).FailedWithMsg("密码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成token
|
||||
token, err := compoment.JWT().GenerateToken(user.Id)
|
||||
if err != nil {
|
||||
utils.GinResponse(c).FailedWithMsg("登陆失败")
|
||||
return
|
||||
}
|
||||
|
||||
utils.GinResponse(c).OKWithData(map[string]any{
|
||||
"token": token,
|
||||
"type": "Bearer",
|
||||
})
|
||||
}
|
||||
|
||||
// GetUser
|
||||
// @description: 获取登陆用户信息
|
||||
// @receiver u
|
||||
// @param c
|
||||
func (u user) GetUser(c *gin.Context) {
|
||||
user, ok := c.Get("user")
|
||||
if !ok {
|
||||
utils.GinResponse(c).FailedWithMsg("获取信息失败")
|
||||
return
|
||||
}
|
||||
data := &vo.User{
|
||||
Id: user.(*entity.User).Id,
|
||||
Name: user.(*entity.User).Name,
|
||||
Avatar: user.(*entity.User).Avatar,
|
||||
Account: user.(*entity.User).Account,
|
||||
Email: user.(*entity.User).Email,
|
||||
IsAdmin: user.(*entity.User).IsAdmin,
|
||||
Status: user.(*entity.User).Status,
|
||||
CreatedAt: user.(*entity.User).CreatedAt,
|
||||
UpdatedAt: user.(*entity.User).UpdatedAt,
|
||||
}
|
||||
utils.GinResponse(c).OKWithData(data)
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package param
|
||||
|
||||
type Login struct {
|
||||
Account string `json:"account" form:"account" binding:"required"`
|
||||
Password string `json:"password" form:"password" binding:"required"`
|
||||
Account string `json:"account" form:"account" binding:"required"`
|
||||
Password string `json:"password" form:"password" binding:"required"`
|
||||
CaptchaId string `json:"captchaId" form:"captchaId" binding:"required"`
|
||||
CaptchaAnswer string `json:"captchaAnswer" form:"captchaAnswer" binding:"required"`
|
||||
}
|
||||
|
49
middleware/authorization.go
Normal file
49
middleware/authorization.go
Normal file
@ -0,0 +1,49 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
"wireguard-dashboard/compoment"
|
||||
"wireguard-dashboard/constant"
|
||||
"wireguard-dashboard/repository"
|
||||
"wireguard-dashboard/utils"
|
||||
)
|
||||
|
||||
// Authorization
|
||||
// @description: 授权中间件
|
||||
// @return gin.HandlerFunc
|
||||
func Authorization() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
token := c.GetHeader("Authorization")
|
||||
if token == "" || !strings.HasPrefix(token, "Bearer ") {
|
||||
utils.GinResponse(c).AuthorizationFailed()
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
userClaims, err := compoment.JWT().ParseToken(token)
|
||||
if err != nil {
|
||||
utils.GinResponse(c).AuthorizationFailed()
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 查询用户
|
||||
user, err := repository.User().GetUserById(userClaims.ID)
|
||||
if err != nil {
|
||||
utils.GinResponse(c).FailedWithMsg("用户不存在")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if user.Status != constant.Normal {
|
||||
utils.GinResponse(c).FailedWithMsg("用户状态异常,请联系管理员处理!")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
// 将用户信息放入上下文
|
||||
c.Set("user", user)
|
||||
c.Next()
|
||||
}
|
||||
}
|
@ -10,171 +10,48 @@ import (
|
||||
)
|
||||
|
||||
type Base struct {
|
||||
Id string `json:"id" gorm:"primaryKey;type:varchar(36);not null;comment:'主键'"`
|
||||
CreatedAt DateTime
|
||||
UpdatedAt DateTime
|
||||
Id string `json:"id" gorm:"primaryKey;type:varchar(36);not null;comment:'主键'"`
|
||||
Timestamp
|
||||
}
|
||||
|
||||
func (b *Base) BeforeCreate(*gorm.DB) (err error) {
|
||||
if b.Id == "" {
|
||||
b.Id = uuid.NewString()
|
||||
b.Id = strings.ReplaceAll(uuid.NewString(), "-", "")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 默认时间格式
|
||||
const dateTimeFormat = "2006-01-02 15:04:05.000"
|
||||
|
||||
// DateTime 自定义时间类型
|
||||
type DateTime time.Time
|
||||
|
||||
// 可能包含的时间格式
|
||||
var formatMap = map[string]string{
|
||||
"yyyy-mm-dd hh:mm:ss": "2006-01-02 15:04:05",
|
||||
"yyyy-mm-dd hh:mm": "2006-01-02 15:04",
|
||||
"yyyy-mm-dd hh": "2006-01-02 15:04",
|
||||
"yyyy-mm-dd": "2006-01-02",
|
||||
"yyyy-mm": "2006-01",
|
||||
"mm-dd": "01-02",
|
||||
"dd-mm-yy hh:mm:ss": "02-01-06 15:04:05",
|
||||
"yyyy/mm/dd hh:mm:ss": "2006/01/02 15:04:05",
|
||||
"yyyy/mm/dd hh:mm": "2006/01/02 15:04",
|
||||
"yyyy/mm/dd hh": "2006/01/02 15",
|
||||
"yyyy/mm/dd": "2006/01/02",
|
||||
"yyyy/mm": "2006/01",
|
||||
"mm/dd": "01/02",
|
||||
"dd/mm/yy hh:mm:ss": "02/01/06 15:04:05",
|
||||
"yyyy": "2006",
|
||||
"mm": "01",
|
||||
"hh:mm:ss": "15:04:05",
|
||||
"mm:ss": "04:05",
|
||||
type JsonTime struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (dt *DateTime) Scan(value interface{}) error {
|
||||
// mysql 内部日期的格式可能是 2006-01-02 15:04:05 +0800 CST 格式,所以检出的时候还需要进行一次格式化
|
||||
tTime, _ := time.Parse("2006-01-02 15:04:05 +0800 CST", value.(time.Time).String())
|
||||
*dt = DateTime(tTime)
|
||||
return nil
|
||||
type Timestamp struct {
|
||||
CreatedAt JsonTime
|
||||
UpdatedAt JsonTime
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (dt DateTime) Value() (dv driver.Value, err error) {
|
||||
// 0001-01-01 00:00:00 属于空值,遇到空值解析成 null 即可
|
||||
if dt.String() == "0001-01-01 00:00:00.000" {
|
||||
return nil, nil
|
||||
func (jt JsonTime) MarshalJSON() ([]byte, error) {
|
||||
if jt.IsZero() {
|
||||
return []byte(`""`), nil
|
||||
}
|
||||
dv, err = []byte(dt.Format(dateTimeFormat)), nil
|
||||
return
|
||||
}
|
||||
|
||||
// 用于 fmt.Println 和后续验证场景
|
||||
func (dt DateTime) String() string {
|
||||
return dt.Format(dateTimeFormat)
|
||||
}
|
||||
|
||||
// Format 格式化
|
||||
func (dt *DateTime) Format(fm string) string {
|
||||
return time.Time(*dt).Format(fm)
|
||||
}
|
||||
|
||||
// AutoParse 假装是个自动解析时间的函数
|
||||
func (dt DateTime) AutoParse(timeStr string) (t time.Time, err error) {
|
||||
// 循环匹配预设的时间格式
|
||||
for _, v := range formatMap {
|
||||
// 尝试解析,没报错就是解析成功了
|
||||
t, err = time.ParseInLocation(v, timeStr, time.Local)
|
||||
if err == nil {
|
||||
// 错误为空,表示匹配上了
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// After 时间比较
|
||||
func (dt *DateTime) After(now time.Time) bool {
|
||||
return time.Time(*dt).After(now)
|
||||
}
|
||||
|
||||
// Before 时间比较
|
||||
func (dt *DateTime) Before(now time.Time) bool {
|
||||
return time.Time(*dt).Before(now)
|
||||
}
|
||||
|
||||
// IBefore 时间比较
|
||||
func (dt *DateTime) IBefore(now DateTime) bool {
|
||||
return dt.Before(time.Time(now))
|
||||
}
|
||||
|
||||
// SubTime 对比
|
||||
func (dt DateTime) SubTime(t time.Time) time.Duration {
|
||||
return dt.ToTime().Sub(t)
|
||||
}
|
||||
|
||||
// Sub 对比
|
||||
func (dt DateTime) Sub(t DateTime) time.Duration {
|
||||
return dt.ToTime().Sub(t.ToTime())
|
||||
}
|
||||
|
||||
// ToTime 转换为golang的时间类型
|
||||
func (dt DateTime) ToTime() time.Time {
|
||||
return time.Time(dt)
|
||||
}
|
||||
|
||||
// IsNil 是否为空值
|
||||
func (dt DateTime) IsNil() bool {
|
||||
return dt.Format(dateTimeFormat) == "0001-01-01 00:00:00.000"
|
||||
}
|
||||
|
||||
// Unix 实现Unix函数
|
||||
func (dt DateTime) Unix() int64 {
|
||||
return dt.ToTime().Unix()
|
||||
}
|
||||
|
||||
// EndOfCentury 获取本世纪最后时间
|
||||
func (dt DateTime) EndOfCentury() DateTime {
|
||||
yearEnd := time.Now().Local().Year()/100*100 + 99
|
||||
return DateTime(time.Date(yearEnd, 12, 31, 23, 59, 59, 999999999, time.Local))
|
||||
}
|
||||
|
||||
// Add
|
||||
// @description: 添加时间
|
||||
// @receiver dt
|
||||
// @param t
|
||||
func (dt DateTime) Add(d time.Duration) DateTime {
|
||||
return DateTime(dt.ToTime().Add(d))
|
||||
}
|
||||
|
||||
// ======== 序列化 JSON ========
|
||||
|
||||
// MarshalJSON 时间到字符串
|
||||
func (dt DateTime) MarshalJSON() ([]byte, error) {
|
||||
// 过滤掉空数据
|
||||
if dt.IsNil() {
|
||||
return []byte("\"\""), nil
|
||||
}
|
||||
output := fmt.Sprintf(`"%s"`, dt.Format("2006-01-02 15:04:05"))
|
||||
output := fmt.Sprintf("\"%s\"", jt.Format("2006-01-02 15:04:05"))
|
||||
return []byte(output), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON 字符串到时间
|
||||
func (dt *DateTime) UnmarshalJSON(b []byte) (err error) {
|
||||
if len(b) == 2 {
|
||||
*dt = DateTime{}
|
||||
return
|
||||
func (jt JsonTime) Value() (driver.Value, error) {
|
||||
var zeroTime time.Time
|
||||
if jt.Time.UnixNano() == zeroTime.UnixNano() {
|
||||
return nil, nil
|
||||
}
|
||||
// 解析指定的格式
|
||||
var now time.Time
|
||||
if strings.HasPrefix(string(b), "\"") {
|
||||
now, err = dt.AutoParse(string(b)[1 : len(b)-1])
|
||||
} else {
|
||||
now, err = dt.AutoParse(string(b))
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
*dt = DateTime(now)
|
||||
return
|
||||
return jt.Time.Format("2006-01-02 15:04:05"), nil
|
||||
}
|
||||
|
||||
func (jt *JsonTime) Scan(v interface{}) error {
|
||||
value, ok := v.(time.Time)
|
||||
if ok {
|
||||
*jt = JsonTime{Time: value}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("can not convert %v to timestamp", v)
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ import "wireguard-dashboard/constant"
|
||||
// @description: 用户信息
|
||||
type User struct {
|
||||
Base
|
||||
Avatar string `json:"avatar" gorm:"type:varchar(255);not null;comment:'头像'"`
|
||||
Name string `json:"name" gorm:"type:varchar(50);not null;comment:'用户名'"`
|
||||
Account string `json:"account" gorm:"type:varchar(50);not null;comment:'账号'"`
|
||||
Email string `json:"email" gorm:"type:varchar(255);default null;comment:'联系邮箱'"`
|
||||
Password string `json:"password" gorm:"type:varchar(255);not null;comment:'密码'"`
|
||||
IsAdmin constant.UserType `json:"isAdmin" gorm:"type:int(1);not null;comment:'是否为管理员'"`
|
||||
Avatar string `json:"avatar" gorm:"type:varchar(255);not null;comment:'头像'"`
|
||||
Name string `json:"name" gorm:"type:varchar(50);not null;comment:'用户名'"`
|
||||
Account string `json:"account" gorm:"type:varchar(50);not null;comment:'账号'"`
|
||||
Email string `json:"email" gorm:"type:varchar(255);default null;comment:'联系邮箱'"`
|
||||
Password string `json:"password" gorm:"type:varchar(255);not null;comment:'密码'"`
|
||||
IsAdmin constant.UserType `json:"isAdmin" gorm:"type:int(1);not null;comment:'是否为管理员'"`
|
||||
Status constant.UserStatus `json:"status" gorm:"type:int(1);not null;comment:'用户状态(0 - 禁用 | 1 - 正常)'"`
|
||||
}
|
||||
|
||||
func (*User) TableName() string {
|
||||
|
20
model/vo/user.go
Normal file
20
model/vo/user.go
Normal file
@ -0,0 +1,20 @@
|
||||
package vo
|
||||
|
||||
import (
|
||||
"wireguard-dashboard/constant"
|
||||
"wireguard-dashboard/model/entity"
|
||||
)
|
||||
|
||||
// User
|
||||
// @description: 用户信息
|
||||
type User struct {
|
||||
Id string `json:"id"` // id
|
||||
Name string `json:"name"` // 用户名
|
||||
Avatar string `json:"avatar"` // 头像
|
||||
Account string `json:"account"` // 账户
|
||||
Email string `json:"email"` // 联系邮箱
|
||||
IsAdmin constant.UserType `json:"isAdmin"` // 管理员
|
||||
Status constant.UserStatus `json:"status"` // 状态
|
||||
CreatedAt entity.JsonTime `json:"createdAt"` // 创建时间
|
||||
UpdatedAt entity.JsonTime `json:"updatedAt"` // 更新时间
|
||||
}
|
34
repository/user.go
Normal file
34
repository/user.go
Normal file
@ -0,0 +1,34 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"wireguard-dashboard/client"
|
||||
"wireguard-dashboard/model/entity"
|
||||
)
|
||||
|
||||
type user struct{}
|
||||
|
||||
func User() user {
|
||||
return user{}
|
||||
}
|
||||
|
||||
// GetUserById
|
||||
// @description: 根据id获取用户信息
|
||||
// @receiver r
|
||||
// @param id
|
||||
// @return *entity.User
|
||||
// @return error
|
||||
func (r user) GetUserById(id string) (data *entity.User, err error) {
|
||||
err = client.DB.Where("id = ?", id).First(&data).Error
|
||||
return
|
||||
}
|
||||
|
||||
// GetUserByAccount
|
||||
// @description: 通过账户号获取用户信息
|
||||
// @receiver r
|
||||
// @param account
|
||||
// @return data
|
||||
// @return err
|
||||
func (r user) GetUserByAccount(account string) (data *entity.User, err error) {
|
||||
err = client.DB.Where("account = ?", account).First(&data).Error
|
||||
return
|
||||
}
|
@ -11,6 +11,6 @@ import (
|
||||
func Captcha(r *gin.Engine) {
|
||||
captcha := r.Group("captcha")
|
||||
{
|
||||
captcha.GET("captcha", api.Captcha().GenerateCaptcha) // 生成验证码
|
||||
captcha.GET("", api.Captcha().GenerateCaptcha) // 生成验证码
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,19 @@ package route
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"wireguard-dashboard/http/api"
|
||||
"wireguard-dashboard/middleware"
|
||||
)
|
||||
|
||||
func UserApi(r *gin.Engine) {
|
||||
// 登陆相关API
|
||||
login := r.Group("/login")
|
||||
{
|
||||
login.POST("", api.UserApi().Login)
|
||||
}
|
||||
|
||||
// 用户登陆后相关的API
|
||||
userApi := r.Group("user")
|
||||
{
|
||||
userApi.POST("/login", api.UserApi().Login) // 登陆
|
||||
userApi.GET("", middleware.Authorization(), api.UserApi().GetUser) // 获取登陆用户信息
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ func (s Script) CreateSuperAdmin() error {
|
||||
Email: "",
|
||||
Password: utils.Password().GenerateHashPassword("admin123"),
|
||||
IsAdmin: constant.SuperAdmin,
|
||||
Status: constant.Normal,
|
||||
}).Error; err != nil {
|
||||
zap.S().Errorf("创建管理员失败: %v", err.Error())
|
||||
}
|
||||
|
@ -35,6 +35,20 @@ func (r ginResponse) FailedWithErr(msg string, err error) {
|
||||
})
|
||||
}
|
||||
|
||||
func (r ginResponse) FailedWithMsg(msg string) {
|
||||
r.c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": msg,
|
||||
})
|
||||
}
|
||||
|
||||
func (r ginResponse) AuthorizationFailed() {
|
||||
r.c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "请先登陆",
|
||||
})
|
||||
}
|
||||
|
||||
func (r ginResponse) OKWithData(data any) {
|
||||
r.c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
|
Loading…
Reference in New Issue
Block a user