add models and jwt
This commit is contained in:
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch Package",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${fileDirname}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
22
conf/conf.ini
Normal file
22
conf/conf.ini
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
[mysql]
|
||||||
|
Type = mysql
|
||||||
|
Host = 127.0.0.1
|
||||||
|
Port = 3306
|
||||||
|
User = root
|
||||||
|
Password = root
|
||||||
|
DB = login
|
||||||
|
Charset = utf8mb4
|
||||||
|
;Prefix = gin_
|
||||||
|
|
||||||
|
[jwt]
|
||||||
|
SecretKey = \x13\xbf\xd2 1\xce\x8b\xc1\t\xc1=\xec\x07\x93\xd4\x9e\xbco\xb0Z
|
||||||
|
|
||||||
|
[project]
|
||||||
|
StaticUrlMapPath = {"assets/static/": "static/", "assets/docs/": "docs/", "media/": "media/"}
|
||||||
|
TemplateGlob = templates/**/*
|
||||||
|
MediaFilePath = "media/upload/"
|
||||||
|
|
||||||
|
[server]
|
||||||
|
Port = 7890
|
||||||
|
ReadTimeout = 60
|
||||||
|
WriteTimeout = 60
|
||||||
65
conf/config.go
Normal file
65
conf/config.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/6/28 21:48
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : config.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-ini/ini"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SqlDataBase struct {
|
||||||
|
Type string
|
||||||
|
Host string
|
||||||
|
Port string
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
DB string
|
||||||
|
Charset string
|
||||||
|
Prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Jwt struct {
|
||||||
|
SecretKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Project struct {
|
||||||
|
StaticUrlMapPath string
|
||||||
|
TemplateGlob string
|
||||||
|
MediaFilePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Port string
|
||||||
|
ReadTimeout time.Duration
|
||||||
|
WriteTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
DataBase = &SqlDataBase{}
|
||||||
|
JwtSecretKey = &Jwt{}
|
||||||
|
ProjectCfg = &Project{}
|
||||||
|
HttpServer = &Server{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetUp() {
|
||||||
|
cfg, err := ini.Load("conf/conf.ini")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := cfg.Section("mysql").MapTo(DataBase); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := cfg.Section("jwt").MapTo(JwtSecretKey); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := cfg.Section("project").MapTo(ProjectCfg); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := cfg.Section("server").MapTo(HttpServer); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
11
go.mod
11
go.mod
@@ -2,7 +2,13 @@ module go_blog
|
|||||||
|
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require github.com/gin-gonic/gin v1.9.1
|
require (
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
|
github.com/gin-gonic/gin v1.9.1
|
||||||
|
github.com/go-ini/ini v1.67.0
|
||||||
|
github.com/jinzhu/gorm v1.9.16
|
||||||
|
golang.org/x/crypto v0.9.0
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
@@ -12,7 +18,9 @@ require (
|
|||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.5.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
@@ -23,7 +31,6 @@ require (
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.9.0 // indirect
|
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.8.0 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.9.0 // indirect
|
||||||
|
|||||||
35
go.sum
35
go.sum
@@ -1,3 +1,5 @@
|
|||||||
|
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||||
|
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||||
@@ -7,12 +9,20 @@ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583j
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||||
|
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||||
|
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
|
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||||
|
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
@@ -20,12 +30,22 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
|||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
|
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||||
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
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/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||||
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
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=
|
||||||
|
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||||
|
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
||||||
|
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
@@ -33,8 +53,12 @@ github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZX
|
|||||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||||
|
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||||
|
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
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 h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
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=
|
||||||
@@ -62,14 +86,25 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
|
|||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
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/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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/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 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
|||||||
82
handlers/response.go
Normal file
82
handlers/response.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/6/28 22:37
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : response.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Success = 200
|
||||||
|
BadRequest = 400
|
||||||
|
Unauthenticated = 401
|
||||||
|
NoPermisson = 403
|
||||||
|
NotFund = 404
|
||||||
|
ServerError = 500
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Ctx *gin.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义基础返回结构体
|
||||||
|
type JsonResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Data interface{} `json:"data,omitempty"`
|
||||||
|
Pager interface{} `json:"pager,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (resp *Response) Response(data interface{}, pager interface{}) {
|
||||||
|
resp.Ctx.JSON(Success, JsonResponse{
|
||||||
|
Code: Success,
|
||||||
|
Msg: "返回成功",
|
||||||
|
Data: data,
|
||||||
|
Pager: pager,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 400错误请求
|
||||||
|
func (resp *Response) BadRequest(msg string) {
|
||||||
|
resp.Ctx.AbortWithStatusJSON(Success, JsonResponse{
|
||||||
|
Code: BadRequest,
|
||||||
|
Msg: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 401未登录验证
|
||||||
|
func (resp *Response) Unauthenticated(msg string) {
|
||||||
|
resp.Ctx.AbortWithStatusJSON(Success, JsonResponse{
|
||||||
|
Code: Unauthenticated,
|
||||||
|
Msg: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 403没有权限
|
||||||
|
func (resp *Response) NoPermisson(msg string) {
|
||||||
|
resp.Ctx.AbortWithStatusJSON(Success, JsonResponse{
|
||||||
|
Code: NoPermisson,
|
||||||
|
Msg: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 404资源不存在
|
||||||
|
func (resp *Response) NotFund(msg string) {
|
||||||
|
resp.Ctx.AbortWithStatusJSON(Success, JsonResponse{
|
||||||
|
Code: NotFund,
|
||||||
|
Msg: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 500服务器出错
|
||||||
|
func (resp *Response) ServerError(msg string) {
|
||||||
|
resp.Ctx.AbortWithStatusJSON(200, JsonResponse{
|
||||||
|
Code: ServerError,
|
||||||
|
Msg: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
127
handlers/users.go
Normal file
127
handlers/users.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/6/28 21:40
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : users.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go_blog/models"
|
||||||
|
"go_blog/pkg/jwt"
|
||||||
|
"go_blog/pkg/util"
|
||||||
|
"go_blog/serializers"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 登录
|
||||||
|
func UsersLoginHandler(ctx *gin.Context) {
|
||||||
|
response := Response{Ctx: ctx}
|
||||||
|
var loginUser serializers.Login
|
||||||
|
if err := ctx.ShouldBind(&loginUser); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
user := loginUser.GetUser()
|
||||||
|
isLoginUser := user.CheckPassword()
|
||||||
|
if !isLoginUser {
|
||||||
|
response.BadRequest("密码错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token, err := jwt.GenToken(user.ID, user.Username)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
data, _ := util.PrecisionLost(user)
|
||||||
|
data["token"] = token
|
||||||
|
response.Response(data, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
func UsersRegisterHandler(ctx *gin.Context) {
|
||||||
|
response := Response{Ctx: ctx}
|
||||||
|
var registerUser serializers.Login
|
||||||
|
if err := ctx.ShouldBind(®isterUser); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
user := registerUser.GetUser()
|
||||||
|
status := user.CheckDuplicateUsername()
|
||||||
|
if status == false {
|
||||||
|
response.BadRequest("用户名已存在")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := user.SetPassword(user.Password); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
user.IsActive = true
|
||||||
|
models.DB.Create(&user)
|
||||||
|
response.Response(nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改用户信息
|
||||||
|
func UsersSetInfoHandler(ctx *gin.Context) {
|
||||||
|
response := Response{Ctx: ctx}
|
||||||
|
jsonData, err := util.GetBodyData(ctx)
|
||||||
|
if err != nil {
|
||||||
|
response.BadRequest("参数解析失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(jsonData)
|
||||||
|
if jsonData == nil {
|
||||||
|
response.BadRequest("获取不到参数")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentUser := jwt.AssertUser(ctx)
|
||||||
|
if currentUser != nil {
|
||||||
|
models.DB.Model(¤tUser).Updates(jsonData)
|
||||||
|
response.Response(currentUser, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改密码
|
||||||
|
func UsersSetPwdHandler(ctx *gin.Context) {
|
||||||
|
response := Response{Ctx: ctx}
|
||||||
|
currentUser := jwt.AssertUser(ctx)
|
||||||
|
if currentUser == nil {
|
||||||
|
response.Unauthenticated("未验证登录")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var user serializers.Account
|
||||||
|
if err := ctx.ShouldBindJSON(&user); err != nil {
|
||||||
|
response.BadRequest(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user.Username != currentUser.Username {
|
||||||
|
response.BadRequest("当前登录用户用户名与输入用户名不符")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if user.OldPwd == user.NewPwd {
|
||||||
|
response.BadRequest("两次输入的密码相同")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if isPwd := currentUser.IsPasswordEqual(user.OldPwd); !isPwd {
|
||||||
|
response.BadRequest("原密码错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := currentUser.SetPassword(user.NewPwd); err != nil {
|
||||||
|
response.BadRequest(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
models.DB.Save(¤tUser)
|
||||||
|
response.Response(nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UsersListHandler(ctx *gin.Context) {
|
||||||
|
response := Response{Ctx: ctx}
|
||||||
|
var pager serializers.Pager
|
||||||
|
pager.InitPager(ctx)
|
||||||
|
var users []models.Account
|
||||||
|
db := models.DB.Model(&users)
|
||||||
|
db.Count(&pager.Total)
|
||||||
|
db.Offset(pager.OffSet).Limit(pager.PageSize).Find(&users)
|
||||||
|
pager.GetPager()
|
||||||
|
response.Response(users, pager)
|
||||||
|
}
|
||||||
55
main.go
55
main.go
@@ -1,6 +1,38 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
import (
|
||||||
|
"flag"
|
||||||
|
"go_blog/conf"
|
||||||
|
"go_blog/handlers"
|
||||||
|
"go_blog/models"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserInfo struct {
|
||||||
|
Name string
|
||||||
|
Gender string
|
||||||
|
Age int
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
var host string
|
||||||
|
var port string
|
||||||
|
var isDebugMode bool
|
||||||
|
var isErrMsg bool
|
||||||
|
var isOrmDebug bool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&host, "h", "127.0.0.1", "主机")
|
||||||
|
flag.StringVar(&port, "p", "", "监听端口")
|
||||||
|
flag.BoolVar(&isDebugMode, "debug", true, "是否开启debug")
|
||||||
|
flag.BoolVar(&isErrMsg, "err", true, "是否返回错误信息")
|
||||||
|
flag.BoolVar(&isOrmDebug, "orm", true, "是否开启gorm的debug信息")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
conf.SetUp()
|
||||||
|
models.SetUp(isOrmDebug)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
@@ -9,9 +41,28 @@ func main() {
|
|||||||
r.GET("/", func(c *gin.Context) {
|
r.GET("/", func(c *gin.Context) {
|
||||||
c.HTML(200, "index.tmpl", nil)
|
c.HTML(200, "index.tmpl", nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
user := UserInfo{
|
||||||
|
Name: "user",
|
||||||
|
Gender: "male",
|
||||||
|
Age: 18,
|
||||||
|
Password: "nothings",
|
||||||
|
}
|
||||||
r.GET("/page/:id", func(c *gin.Context) {
|
r.GET("/page/:id", func(c *gin.Context) {
|
||||||
id := c.Param("id")
|
id := c.Param("id")
|
||||||
c.HTML(200, "page"+id+".tmpl", nil)
|
c.HTML(200, "page"+id+".tmpl", map[string]interface{}{
|
||||||
|
"title": "这个是titile,传入templates中的",
|
||||||
|
"user": user,
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
r.GET("/login", func(c *gin.Context) {
|
||||||
|
c.HTML(200, "login.tmpl", map[string]interface{}{
|
||||||
|
"title": "这个是titile,传入templates中的",
|
||||||
|
"user": user,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
r.POST("/login", handlers.UsersLoginHandler)
|
||||||
r.Run(":8080")
|
r.Run(":8080")
|
||||||
}
|
}
|
||||||
|
|||||||
56
models/init.go
Normal file
56
models/init.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/6/28 21:46
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : init.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go_blog/conf"
|
||||||
|
"go_blog/pkg/util"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DB *gorm.DB
|
||||||
|
|
||||||
|
func SetUp(isOrmDebug bool) {
|
||||||
|
conUri := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local",
|
||||||
|
conf.DataBase.User,
|
||||||
|
conf.DataBase.Password,
|
||||||
|
conf.DataBase.Host,
|
||||||
|
conf.DataBase.Port,
|
||||||
|
conf.DataBase.DB,
|
||||||
|
conf.DataBase.Charset)
|
||||||
|
db, err := gorm.Open(conf.DataBase.Type, conUri)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
DB = db
|
||||||
|
DB.LogMode(isOrmDebug)
|
||||||
|
gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
|
||||||
|
return conf.DataBase.Prefix + defaultTableName
|
||||||
|
}
|
||||||
|
|
||||||
|
DB.AutoMigrate(&Account{})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseModel struct {
|
||||||
|
ID uint64 `gorm:"primary_key'" json:"id"`
|
||||||
|
CreatedAt time.Time `json:"-"`
|
||||||
|
UpdatedAt time.Time `json:"-"`
|
||||||
|
DeletedAt *time.Time `sql:"index" json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成全局唯一ID
|
||||||
|
func (m *BaseModel) BeforeCreate(scope *gorm.Scope) error {
|
||||||
|
if m.ID == 0 {
|
||||||
|
m.ID = util.GenSonyFlakeId()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
68
models/users.go
Normal file
68
models/users.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/6/28 22:01
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : users.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const PasswordCryptLevel = 12
|
||||||
|
|
||||||
|
type Account struct {
|
||||||
|
BaseModel
|
||||||
|
Username string `gorm:"column:username;not null;unique_index;comment:'用户名'" json:"username" form:"username"`
|
||||||
|
Password string `gorm:"column:password;comment:'密码'" form:"password" json:"-"`
|
||||||
|
Name string `form:"name" json:"name"`
|
||||||
|
IsActive bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Account) TableName() string {
|
||||||
|
return "user_accounts"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Account) GetUserByID(id uint) *Account {
|
||||||
|
DB.Model(&Account{}).First(a, id)
|
||||||
|
if a.ID > 0 {
|
||||||
|
return a
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置密码加密
|
||||||
|
func (a *Account) SetPassword(password string) error {
|
||||||
|
p, err := bcrypt.GenerateFromPassword([]byte(password), PasswordCryptLevel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.Password = string(p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证登录帐户密码合法性
|
||||||
|
func (a *Account) CheckPassword() bool {
|
||||||
|
password := a.Password
|
||||||
|
DB.Where("username = ?", a.Username).First(&a)
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(a.Password), []byte(password))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证登录帐户密码合法性
|
||||||
|
func (a *Account) IsPasswordEqual(password string) bool {
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(a.Password), []byte(password))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证用户民重复
|
||||||
|
func (a *Account) CheckDuplicateUsername() bool {
|
||||||
|
var count int
|
||||||
|
if DB.Model(&Account{}).Where("username=?", a.Username).Count(&count); count > 0 {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
77
pkg/jwt/auth.go
Normal file
77
pkg/jwt/auth.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/6/29 9:05
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : auth.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jwt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go_blog/conf"
|
||||||
|
"go_blog/models"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 定义jwt载荷
|
||||||
|
type UserClaims struct {
|
||||||
|
jwt.StandardClaims
|
||||||
|
ID uint64 `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据payload查询user返回
|
||||||
|
func (c *UserClaims) GetUserByID() *models.Account {
|
||||||
|
var user models.Account
|
||||||
|
models.DB.Model(&models.Account{}).First(&user, c.ID)
|
||||||
|
if user.ID > 0 {
|
||||||
|
return &user
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成jwt token字符串
|
||||||
|
func GenToken(id uint64, username string) (string, error) {
|
||||||
|
expiredTime := time.Now().Add(time.Hour * time.Duration(24)).Unix()
|
||||||
|
claims := UserClaims{
|
||||||
|
jwt.StandardClaims{
|
||||||
|
ExpiresAt: expiredTime,
|
||||||
|
},
|
||||||
|
id,
|
||||||
|
username,
|
||||||
|
}
|
||||||
|
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
token, err := tokenClaims.SignedString([]byte(conf.JwtSecretKey.SecretKey))
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证token合法性
|
||||||
|
func ValidateJwtToken(token string) (*UserClaims, error) {
|
||||||
|
tokenClaims, err := jwt.ParseWithClaims(token, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return []byte(conf.JwtSecretKey.SecretKey), nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if tokenClaims != nil {
|
||||||
|
if claims, ok := tokenClaims.Claims.(*UserClaims); ok && tokenClaims.Valid {
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 断言设定ctx的当前用户
|
||||||
|
func AssertUser(ctx *gin.Context) *models.Account {
|
||||||
|
currentUser, isExists := ctx.Get("CurrentUser")
|
||||||
|
if !isExists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
user, ok := currentUser.(*models.Account)
|
||||||
|
if ok {
|
||||||
|
return user
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
44
pkg/util/request.go
Normal file
44
pkg/util/request.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/6/29 14:40
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : body.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 反序列化request.body中的json数据为map
|
||||||
|
func GetBodyData(ctx *gin.Context) (map[string]interface{}, error) {
|
||||||
|
bdata := make([]byte, 1024)
|
||||||
|
length, err := ctx.Request.Body.Read(bdata)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var data map[string]interface{}
|
||||||
|
str := string(bdata[:length])
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(str))
|
||||||
|
decoder.UseNumber()
|
||||||
|
err1 := decoder.Decode(&data)
|
||||||
|
if err1 != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建文件url连接主机端口全链接 "https://192.168.11.121:7889/meida/upload/..."
|
||||||
|
func BuildAbsoluteUri(ctx *gin.Context, filePath string) string {
|
||||||
|
host := ctx.Request.Host
|
||||||
|
schema := ctx.Request.Header.Get("X-Forwarded-Proto")
|
||||||
|
if schema == "https" {
|
||||||
|
return fmt.Sprintf("https://%s/%s", host, filePath)
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("http://%s/%s", host, filePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
183
pkg/util/sonyflake.go
Normal file
183
pkg/util/sonyflake.go
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
// Package sonyflake implements Sonyflake, a distributed unique ID generator inspired by Twitter's Snowflake.
|
||||||
|
//
|
||||||
|
// A Sonyflake ID is composed of
|
||||||
|
// 39 bits for time in units of 10 msec
|
||||||
|
// 8 bits for a sequence number
|
||||||
|
// 16 bits for a machine id
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These constants are the bit lengths of Sonyflake ID parts.
|
||||||
|
const (
|
||||||
|
BitLenTime = 41 // bit length of time
|
||||||
|
BitLenSequence = 10 // bit length of sequence number
|
||||||
|
BitLenMachineID = 53 - BitLenTime - BitLenSequence // bit length of machine id
|
||||||
|
)
|
||||||
|
|
||||||
|
// Settings configures Sonyflake:
|
||||||
|
//
|
||||||
|
// StartTime is the time since which the Sonyflake time is defined as the elapsed time.
|
||||||
|
// If StartTime is 0, the start time of the Sonyflake is set to "2014-09-01 00:00:00 +0000 UTC".
|
||||||
|
// If StartTime is ahead of the current time, Sonyflake is not created.
|
||||||
|
//
|
||||||
|
// MachineID returns the unique ID of the Sonyflake instance.
|
||||||
|
// If MachineID returns an error, Sonyflake is not created.
|
||||||
|
// If MachineID is nil, default MachineID is used.
|
||||||
|
// Default MachineID returns the lower 16 bits of the private IP address.
|
||||||
|
//
|
||||||
|
// CheckMachineID validates the uniqueness of the machine ID.
|
||||||
|
// If CheckMachineID returns false, Sonyflake is not created.
|
||||||
|
// If CheckMachineID is nil, no validation is done.
|
||||||
|
type Settings struct {
|
||||||
|
StartTime time.Time
|
||||||
|
MachineID func() (uint16, error)
|
||||||
|
CheckMachineID func(uint16) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sonyflake is a distributed unique ID generator.
|
||||||
|
type Sonyflake struct {
|
||||||
|
mutex *sync.Mutex
|
||||||
|
startTime int64
|
||||||
|
elapsedTime int64
|
||||||
|
sequence uint16
|
||||||
|
machineID uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSonyflake returns a new Sonyflake configured with the given Settings.
|
||||||
|
// NewSonyflake returns nil in the following cases:
|
||||||
|
// - Settings.StartTime is ahead of the current time.
|
||||||
|
// - Settings.MachineID returns an error.
|
||||||
|
// - Settings.CheckMachineID returns false.
|
||||||
|
func NewSonyflake(st Settings) *Sonyflake {
|
||||||
|
sf := new(Sonyflake)
|
||||||
|
sf.mutex = new(sync.Mutex)
|
||||||
|
sf.sequence = uint16(1<<BitLenSequence - 1)
|
||||||
|
|
||||||
|
if st.StartTime.After(time.Now()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if st.StartTime.IsZero() {
|
||||||
|
sf.startTime = toSonyflakeTime(time.Date(2014, 9, 1, 0, 0, 0, 0, time.UTC))
|
||||||
|
} else {
|
||||||
|
sf.startTime = toSonyflakeTime(st.StartTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if st.MachineID == nil {
|
||||||
|
sf.machineID, err = lower16BitPrivateIP()
|
||||||
|
} else {
|
||||||
|
sf.machineID, err = st.MachineID()
|
||||||
|
}
|
||||||
|
if err != nil || (st.CheckMachineID != nil && !st.CheckMachineID(sf.machineID)) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return sf
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextID generates a next unique ID.
|
||||||
|
// After the Sonyflake time overflows, NextID returns an error.
|
||||||
|
func (sf *Sonyflake) NextID() (uint64, error) {
|
||||||
|
const maskSequence = uint16(1<<BitLenSequence - 1)
|
||||||
|
|
||||||
|
sf.mutex.Lock()
|
||||||
|
defer sf.mutex.Unlock()
|
||||||
|
|
||||||
|
current := currentElapsedTime(sf.startTime)
|
||||||
|
if sf.elapsedTime < current {
|
||||||
|
sf.elapsedTime = current
|
||||||
|
sf.sequence = 0
|
||||||
|
} else { // sf.elapsedTime >= current
|
||||||
|
sf.sequence = (sf.sequence + 1) & maskSequence
|
||||||
|
if sf.sequence == 0 {
|
||||||
|
sf.elapsedTime++
|
||||||
|
overtime := sf.elapsedTime - current
|
||||||
|
time.Sleep(sleepTime((overtime)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sf.toID()
|
||||||
|
}
|
||||||
|
|
||||||
|
const sonyflakeTimeUnit = 1e7 // nsec, i.e. 10 msec
|
||||||
|
|
||||||
|
func toSonyflakeTime(t time.Time) int64 {
|
||||||
|
return t.UTC().UnixNano() / sonyflakeTimeUnit
|
||||||
|
}
|
||||||
|
|
||||||
|
func currentElapsedTime(startTime int64) int64 {
|
||||||
|
return toSonyflakeTime(time.Now()) - startTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func sleepTime(overtime int64) time.Duration {
|
||||||
|
return time.Duration(overtime)*10*time.Millisecond -
|
||||||
|
time.Duration(time.Now().UTC().UnixNano()%sonyflakeTimeUnit)*time.Nanosecond
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sf *Sonyflake) toID() (uint64, error) {
|
||||||
|
if sf.elapsedTime >= 1<<BitLenTime {
|
||||||
|
return 0, errors.New("over the time limit")
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint64(sf.elapsedTime)<<(BitLenSequence+BitLenMachineID) |
|
||||||
|
uint64(sf.sequence)<<BitLenMachineID |
|
||||||
|
uint64(sf.machineID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func privateIPv4() (net.IP, error) {
|
||||||
|
as, err := net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range as {
|
||||||
|
ipnet, ok := a.(*net.IPNet)
|
||||||
|
if !ok || ipnet.IP.IsLoopback() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := ipnet.IP.To4()
|
||||||
|
if isPrivateIPv4(ip) {
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("no private ip address")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPrivateIPv4(ip net.IP) bool {
|
||||||
|
return ip != nil &&
|
||||||
|
(ip[0] == 10 || ip[0] == 172 && (ip[1] >= 16 && ip[1] < 32) || ip[0] == 192 && ip[1] == 168)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lower16BitPrivateIP() (uint16, error) {
|
||||||
|
ip, err := privateIPv4()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint16(ip[2])<<8 + uint16(ip[3]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompose returns a set of Sonyflake ID parts.
|
||||||
|
func Decompose(id uint64) map[string]uint64 {
|
||||||
|
const maskSequence = uint64((1<<BitLenSequence - 1) << BitLenMachineID)
|
||||||
|
const maskMachineID = uint64(1<<BitLenMachineID - 1)
|
||||||
|
|
||||||
|
msb := id >> 63
|
||||||
|
time := id >> (BitLenSequence + BitLenMachineID)
|
||||||
|
sequence := id & maskSequence >> BitLenMachineID
|
||||||
|
machineID := id & maskMachineID
|
||||||
|
return map[string]uint64{
|
||||||
|
"id": id,
|
||||||
|
"msb": msb,
|
||||||
|
"time": time,
|
||||||
|
"sequence": sequence,
|
||||||
|
"machine-id": machineID,
|
||||||
|
}
|
||||||
|
}
|
||||||
42
pkg/util/util.go
Normal file
42
pkg/util/util.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/7/15 23:27
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : util.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// 判断所给路径文件/文件夹是否存在
|
||||||
|
func FileOrDirExists(path string) bool {
|
||||||
|
_, err := os.Stat(path) //os.Stat获取文件信息
|
||||||
|
if err != nil {
|
||||||
|
if os.IsExist(err) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解决json字符串整型精度缺失
|
||||||
|
func PrecisionLost(data interface{}) (map[string]interface{}, error) {
|
||||||
|
bdata, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var val map[string]interface{}
|
||||||
|
d := json.NewDecoder(bytes.NewBuffer(bdata))
|
||||||
|
d.UseNumber()
|
||||||
|
err = d.Decode(&val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
19
pkg/util/uuid.go
Normal file
19
pkg/util/uuid.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
var t = time.Unix(1594909810, 0)
|
||||||
|
|
||||||
|
var flake = NewSonyflake(Settings{
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
func GenSonyFlakeId() uint64 {
|
||||||
|
uuid, err := flake.NextID()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
30
serializers/pagination.go
Normal file
30
serializers/pagination.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/7/16 23:44
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : common.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package serializers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pager struct {
|
||||||
|
Page int `json:"page" form:"page"`
|
||||||
|
PageSize int `json:"pageSize" form:"pageSize"`
|
||||||
|
OffSet int `json:"-"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
MaxPage int `json:"maxPage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pager) InitPager(ctx *gin.Context) {
|
||||||
|
p.Page, _ = strconv.Atoi(ctx.DefaultQuery("page", "1"))
|
||||||
|
p.PageSize, _ = strconv.Atoi(ctx.DefaultQuery("pageSize", "10"))
|
||||||
|
p.OffSet = (p.Page - 1) * p.PageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pager) GetPager() {
|
||||||
|
p.MaxPage = int(p.Total / p.PageSize) + 1
|
||||||
|
}
|
||||||
27
serializers/users.go
Normal file
27
serializers/users.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
@Time : 2020/6/28 22:16
|
||||||
|
@Author : xuyiqing
|
||||||
|
@File : users.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
package serializers
|
||||||
|
|
||||||
|
import "go_blog/models"
|
||||||
|
|
||||||
|
type Login struct {
|
||||||
|
Username string `form:"usernmae"; json:"username"`
|
||||||
|
Password string `form:"password"; json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Login) GetUser() *models.Account {
|
||||||
|
return &models.Account{
|
||||||
|
Username: l.Username,
|
||||||
|
Password: l.Password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Account struct {
|
||||||
|
Username string `form:"username" json:"username"`
|
||||||
|
OldPwd string `form:"oldPwd" json:"oldPwd"`
|
||||||
|
NewPwd string `form:"newPwd"json:"newPwd"`
|
||||||
|
}
|
||||||
33
templates/login.tmpl
Normal file
33
templates/login.tmpl
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
<div class="typecho-login-wrap">
|
||||||
|
<div class="typecho-login">
|
||||||
|
<h1><a href="login.html" class="i-logo">登录</a></h1>
|
||||||
|
<form action="login" method="post" name="login" role="form">
|
||||||
|
<p>
|
||||||
|
<label for="name" class="sr-only">{{.user.Name}}</label>
|
||||||
|
<input type="text" id="name" name="usernmae" value="{{.user.Name}}" placeholder="{{.user.Name}}" class="text-l w-100" autofocus />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="password" class="sr-only">{{.user.Password}}</label>
|
||||||
|
<input type="password" id="password" name="password" class="text-l w-100" placeholder="{{.user.Password}}" />
|
||||||
|
</p>
|
||||||
|
<p class="submit">
|
||||||
|
<button type="submit" class="btn btn-l w-100 primary">'登录'</button>
|
||||||
|
<input type="hidden" name="referer" value="'referer'" />
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label for="remember">
|
||||||
|
<input type="checkbox" name="remember" class="checkbox" value="1" id="remember" /> '下次自动登录'
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('#name').focus();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -8,5 +8,8 @@
|
|||||||
<body>
|
<body>
|
||||||
<h1>Page 1</h1>
|
<h1>Page 1</h1>
|
||||||
<p>This is the content of page 1.</p>
|
<p>This is the content of page 1.</p>
|
||||||
|
<h1>{{.title}}</h1>
|
||||||
|
<h2>{{.user.Name}}</h2>
|
||||||
|
<h3>{{.user.Age}}</h3>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user