add models and jwt

This commit is contained in:
张超
2024-01-10 16:05:15 +08:00
parent 45bc7c5140
commit 2455f0d897
19 changed files with 990 additions and 4 deletions

15
.vscode/launch.json vendored Normal file
View 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
View 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
View 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
View File

@@ -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
View File

@@ -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
View 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
View 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(&registerUser); 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(&currentUser).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(&currentUser)
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
View File

@@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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>

View File

@@ -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>