From 0a3be6cf9ed5509ceb199041862e0b57e9cd4a8b Mon Sep 17 00:00:00 2001 From: yv1ing Date: Thu, 28 Aug 2025 17:24:32 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E6=90=AD=E5=BB=BA=E5=8F=8A=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=99=BB=E5=BD=95=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 21 ++--- configs/config.toml | 13 +++ go.mod | 48 ++++++++++ go.sum | 111 ++++++++++++++++++++++++ internal/api/system/user_api.go | 58 +++++++++++++ internal/auth/jwt.go | 55 ++++++++++++ internal/core/bootstrap.go | 49 +++++++++++ internal/core/config/global.go | 18 ++++ internal/core/config/mysql.go | 14 +++ internal/core/initialize/config.go | 20 +++++ internal/core/initialize/database.go | 41 +++++++++ internal/core/initialize/engine.go | 20 +++++ internal/core/initialize/user.go | 26 ++++++ internal/model/system/base.go | 12 +++ internal/model/system/user.go | 19 ++++ internal/repository/repository.go | 22 +++++ internal/repository/system/user_repo.go | 42 +++++++++ internal/router/router.go | 19 ++++ internal/service/system/user_service.go | 40 +++++++++ main.go | 16 ++++ pkg/encrypt/sha256.go | 22 +++++ pkg/logger/logger.go | 66 ++++++++++++++ 22 files changed, 736 insertions(+), 16 deletions(-) create mode 100644 configs/config.toml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/api/system/user_api.go create mode 100644 internal/auth/jwt.go create mode 100644 internal/core/bootstrap.go create mode 100644 internal/core/config/global.go create mode 100644 internal/core/config/mysql.go create mode 100644 internal/core/initialize/config.go create mode 100644 internal/core/initialize/database.go create mode 100644 internal/core/initialize/engine.go create mode 100644 internal/core/initialize/user.go create mode 100644 internal/model/system/base.go create mode 100644 internal/model/system/user.go create mode 100644 internal/repository/repository.go create mode 100644 internal/repository/system/user_repo.go create mode 100644 internal/router/router.go create mode 100644 internal/service/system/user_service.go create mode 100644 main.go create mode 100644 pkg/encrypt/sha256.go create mode 100644 pkg/logger/logger.go diff --git a/.gitignore b/.gitignore index aaadf73..85aa33d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,21 @@ -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib -# Test binary, built with `go test -c` *.test - -# Code coverage profiles and other test artifacts *.out -coverage.* *.coverprofile + +coverage.* profile.cov -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file go.work go.work.sum -# env file .env +.idea/ +.vscode/ -# Editor/IDE -# .idea/ -# .vscode/ +*.log diff --git a/configs/config.toml b/configs/config.toml new file mode 100644 index 0000000..a694c37 --- /dev/null +++ b/configs/config.toml @@ -0,0 +1,13 @@ +# 系统运行设置 +ListenHost = "127.0.0.1" +ListenPort = 8888 +SecretKey = "" +RootName = "root" +RootPass = "123456" + +[Mysql] +Host = "" +Port = 3306 +Username = "" +Password = "" +Database = "ga" \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b29ff52 --- /dev/null +++ b/go.mod @@ -0,0 +1,48 @@ +module gin-admin + +go 1.25.0 + +require ( + github.com/BurntSushi/toml v1.5.0 + github.com/gin-gonic/gin v1.10.1 + github.com/golang-jwt/jwt/v5 v5.3.0 + go.uber.org/zap v1.27.0 + gorm.io/driver/mysql v1.6.0 + gorm.io/gorm v1.30.2 +) + +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bytedance/sonic v1.14.0 // indirect + github.com/bytedance/sonic/loader v0.3.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect + github.com/gabriel-vasile/mimetype v1.4.10 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.27.0 // indirect + github.com/go-sql-driver/mysql v1.9.3 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.3.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/arch v0.20.0 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + google.golang.org/protobuf v1.36.8 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..0ed55c5 --- /dev/null +++ b/go.sum @@ -0,0 +1,111 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= +github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= +github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= +github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +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= +github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= +github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +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/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= +github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/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.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +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/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +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= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pkg/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/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/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= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= +github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= +golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg= +gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo= +gorm.io/gorm v1.30.2 h1:f7bevlVoVe4Byu3pmbWPVHnPsLoWaMjEb7/clyr9Ivs= +gorm.io/gorm v1.30.2/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= diff --git a/internal/api/system/user_api.go b/internal/api/system/user_api.go new file mode 100644 index 0000000..9bfb65d --- /dev/null +++ b/internal/api/system/user_api.go @@ -0,0 +1,58 @@ +package system + +import ( + "github.com/gin-gonic/gin" + "net/http" + + systemmodel "gin-admin/internal/model/system" + systemservice "gin-admin/internal/service/system" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 16:29 +// @Desc: 系统用户服务接口 + +type SysUserLoginReq struct { + Username string `json:"username"` + Password string `json:"password"` +} + +func SysUserLoginHandler(ctx *gin.Context) { + var req SysUserLoginReq + + err := ctx.ShouldBindJSON(&req) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusBadRequest, systemmodel.Response{ + Code: http.StatusBadRequest, + Info: "请求参数非法", + }) + return + } + + jwtToken, err := systemservice.SysUserLogin(req.Username, req.Password) + if err != nil { + ctx.AbortWithStatusJSON(http.StatusInternalServerError, systemmodel.Response{ + Code: http.StatusInternalServerError, + Info: "登录请求失败:" + err.Error(), + }) + return + } + + if jwtToken == "" { + ctx.AbortWithStatusJSON(http.StatusForbidden, systemmodel.Response{ + Code: http.StatusForbidden, + Info: "登录请求失败:账号或密码错误", + }) + return + } else { + ctx.AbortWithStatusJSON(http.StatusOK, systemmodel.Response{ + Code: http.StatusOK, + Info: "登录请求成功", + Data: gin.H{ + "token": jwtToken, + }, + }) + return + } +} diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go new file mode 100644 index 0000000..94331f6 --- /dev/null +++ b/internal/auth/jwt.go @@ -0,0 +1,55 @@ +package auth + +import ( + "errors" + "fmt" + "gin-admin/internal/core/config" + "github.com/golang-jwt/jwt/v5" + "time" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 15:54 +// @Desc: jwt鉴权方法 + +type AccessClaims struct { + ID uint `json:"id"` + Username string `json:"username"` + jwt.RegisteredClaims +} + +func CreateAccessToken(ID uint, username string, ttl time.Duration) (string, error) { + jwtSecret := []byte(config.Config.SecretKey) + + claims := AccessClaims{ + ID: ID, + Username: username, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: "gin-admin", + IssuedAt: jwt.NewNumericDate(time.Now()), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(ttl)), + ID: fmt.Sprintf("%d-%d", ID, time.Now().UnixNano()), + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString(jwtSecret) +} + +func ParseAccessToken(tokenStr string) (*AccessClaims, error) { + jwtSecret := []byte(config.Config.SecretKey) + token, err := jwt.ParseWithClaims(tokenStr, &AccessClaims{}, func(token *jwt.Token) (interface{}, error) { + return jwtSecret, nil + }) + + if err != nil { + return nil, err + } + + if claims, ok := token.Claims.(*AccessClaims); ok && token.Valid { + return claims, nil + } + + return nil, errors.New("token非法") +} diff --git a/internal/core/bootstrap.go b/internal/core/bootstrap.go new file mode 100644 index 0000000..da4467b --- /dev/null +++ b/internal/core/bootstrap.go @@ -0,0 +1,49 @@ +package core + +import ( + "fmt" + "gin-admin/internal/core/config" + "gin-admin/internal/core/initialize" + "gin-admin/pkg/logger" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 13:58 +// @Desc: API服务入口 + +func Start() { + var err error + + // 加载配置 + err = initialize.InitConfig() + if err != nil { + logger.Error("加载配置失败:", err) + return + } + + // 初始化数据库 + err = initialize.InitDatabase() + if err != nil { + logger.Error("初始化数据库失败:", err) + return + } + + // 初始化系统用户 + err = initialize.InitSysUser() + if err != nil { + logger.Error("初始化系统用户失败:", err) + return + } + + // 初始化引擎 + eng := initialize.InitEngine() + addr := fmt.Sprintf("%s:%d", config.Config.ListenHost, config.Config.ListenPort) + + // 启动引擎 + logger.Info("正在启动引擎,监听在:", addr) + err = eng.Run(addr) + if err != nil { + logger.Error("启动引擎失败:", err) + } +} diff --git a/internal/core/config/global.go b/internal/core/config/global.go new file mode 100644 index 0000000..be5e88b --- /dev/null +++ b/internal/core/config/global.go @@ -0,0 +1,18 @@ +package config + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 14:01 +// @Desc: 系统全局配置 + +type globalConfig struct { + ListenHost string + ListenPort uint + SecretKey string + RootName string + RootPass string + + Mysql mysqlConfig +} + +var Config *globalConfig diff --git a/internal/core/config/mysql.go b/internal/core/config/mysql.go new file mode 100644 index 0000000..f881ffa --- /dev/null +++ b/internal/core/config/mysql.go @@ -0,0 +1,14 @@ +package config + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 14:24 +// @Desc: MySQL配置 + +type mysqlConfig struct { + Host string + Port uint + Username string + Password string + Database string +} diff --git a/internal/core/initialize/config.go b/internal/core/initialize/config.go new file mode 100644 index 0000000..daab0e3 --- /dev/null +++ b/internal/core/initialize/config.go @@ -0,0 +1,20 @@ +package initialize + +import ( + "gin-admin/internal/core/config" + "github.com/BurntSushi/toml" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 14:06 +// @Desc: 初始化系统配置 + +func InitConfig() error { + _, err := toml.DecodeFile("configs/config.toml", &config.Config) + if err != nil { + return err + } + + return nil +} diff --git a/internal/core/initialize/database.go b/internal/core/initialize/database.go new file mode 100644 index 0000000..296c211 --- /dev/null +++ b/internal/core/initialize/database.go @@ -0,0 +1,41 @@ +package initialize + +import ( + "fmt" + "gin-admin/internal/core/config" + "gin-admin/internal/repository" + "gorm.io/driver/mysql" + "gorm.io/gorm" + + systemmodel "gin-admin/internal/model/system" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 14:22 +// @Desc: 初始化mysql数据库 + +func dsn() string { + return fmt.Sprintf( + "%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", + config.Config.Mysql.Username, + config.Config.Mysql.Password, + config.Config.Mysql.Host, + config.Config.Mysql.Port, + config.Config.Mysql.Database, + ) +} + +func InitDatabase() error { + db, err := gorm.Open(mysql.Open(dsn()), &gorm.Config{}) + if err != nil { + return err + } + + err = db.AutoMigrate( + &systemmodel.User{}, + ) + + repository.SetupRepository(db) + return nil +} diff --git a/internal/core/initialize/engine.go b/internal/core/initialize/engine.go new file mode 100644 index 0000000..46e7759 --- /dev/null +++ b/internal/core/initialize/engine.go @@ -0,0 +1,20 @@ +package initialize + +import ( + "gin-admin/internal/router" + "github.com/gin-gonic/gin" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 13:59 +// @Desc: 初始化gin引擎 + +func InitEngine() *gin.Engine { + gin.SetMode(gin.ReleaseMode) + + eng := gin.New() + router.SetupRoutes(eng) + + return eng +} diff --git a/internal/core/initialize/user.go b/internal/core/initialize/user.go new file mode 100644 index 0000000..18d732a --- /dev/null +++ b/internal/core/initialize/user.go @@ -0,0 +1,26 @@ +package initialize + +import ( + "gin-admin/internal/core/config" + "gin-admin/internal/repository" + "gin-admin/pkg/encrypt" + + systemmodel "gin-admin/internal/model/system" + systemrepository "gin-admin/internal/repository/system" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 17:05 +// @Desc: 初始化系统用户 + +func InitSysUser() error { + return systemrepository.CreateUser(repository.Repo.DB, &systemmodel.User{ + IsActive: true, + Username: config.Config.RootName, + Password: encrypt.Sha256String(config.Config.RootPass, config.Config.SecretKey), + Avatar: "/logo.png", + Email: "root@gin-admin.cn", + Phone: "18888888888", + }) +} diff --git a/internal/model/system/base.go b/internal/model/system/base.go new file mode 100644 index 0000000..aeca096 --- /dev/null +++ b/internal/model/system/base.go @@ -0,0 +1,12 @@ +package system + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 16:00 +// @Desc: 系统基础数据模型 + +type Response struct { + Code int `json:"code"` + Info string `json:"info"` + Data any `json:"data"` +} diff --git a/internal/model/system/user.go b/internal/model/system/user.go new file mode 100644 index 0000000..8fc2c91 --- /dev/null +++ b/internal/model/system/user.go @@ -0,0 +1,19 @@ +package system + +import "gorm.io/gorm" + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 15:46 +// @Desc: 系统用户角色模型 + +type User struct { + gorm.Model + + IsActive bool `gorm:"default:true"` + Username string `gorm:"uniqueIndex;size:255"` + Password string + Avatar string + Email string + Phone string +} diff --git a/internal/repository/repository.go b/internal/repository/repository.go new file mode 100644 index 0000000..7e83b9f --- /dev/null +++ b/internal/repository/repository.go @@ -0,0 +1,22 @@ +package repository + +import ( + "gorm.io/gorm" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 14:34 +// @Desc: 数据操作的抽象封装 + +type repository struct { + DB *gorm.DB +} + +var Repo *repository + +func SetupRepository(db *gorm.DB) { + Repo = &repository{ + DB: db, + } +} diff --git a/internal/repository/system/user_repo.go b/internal/repository/system/user_repo.go new file mode 100644 index 0000000..bb96406 --- /dev/null +++ b/internal/repository/system/user_repo.go @@ -0,0 +1,42 @@ +package system + +import ( + "gorm.io/gorm" + + systemmodel "gin-admin/internal/model/system" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 16:33 +// @Desc: 系统用户数据库操作实现 + +func CreateUser(db *gorm.DB, user *systemmodel.User) error { + return db.Create(user).Error +} + +func DeleteUser(db *gorm.DB, id uint) error { + return db.Delete(&systemmodel.User{}, id).Error +} + +func UpdateUser(db *gorm.DB, user *systemmodel.User) error { + return db.Save(user).Error +} + +func GetUserByID(db *gorm.DB, id uint) (*systemmodel.User, error) { + var user systemmodel.User + err := db.First(&user, id).Error + if err != nil { + return nil, err + } + return &user, nil +} + +func GetUserByUsername(db *gorm.DB, username string) (*systemmodel.User, error) { + var user systemmodel.User + err := db.Where("username = ?", username).First(&user).Error + if err != nil { + return nil, err + } + return &user, nil +} diff --git a/internal/router/router.go b/internal/router/router.go new file mode 100644 index 0000000..33e23cd --- /dev/null +++ b/internal/router/router.go @@ -0,0 +1,19 @@ +package router + +import ( + "github.com/gin-gonic/gin" + + systemapi "gin-admin/internal/api/system" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 16:17 +// @Desc: 路由注册入口 + +func SetupRoutes(eng *gin.Engine) { + api := eng.Group("/api") + + /* 系统内置接口 */ + api.POST("/sys/login", systemapi.SysUserLoginHandler) +} diff --git a/internal/service/system/user_service.go b/internal/service/system/user_service.go new file mode 100644 index 0000000..a6777f9 --- /dev/null +++ b/internal/service/system/user_service.go @@ -0,0 +1,40 @@ +package system + +import ( + "errors" + "gin-admin/internal/auth" + "gin-admin/internal/core/config" + "gin-admin/internal/repository" + "gin-admin/pkg/encrypt" + "gorm.io/gorm" + + systemrepository "gin-admin/internal/repository/system" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 16:30 +// @Desc: 系统用户服务实现 + +// SysUserLogin 系统用户登录 +func SysUserLogin(username, password string) (string, error) { + user, err := systemrepository.GetUserByUsername(repository.Repo.DB, username) + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return "", errors.New("系统内部错误") + } + + if errors.Is(err, gorm.ErrRecordNotFound) || encrypt.Sha256String(password, config.Config.SecretKey) != user.Password { + return "", nil + } + + if !user.IsActive { + return "", errors.New("用户已被禁用") + } + + jwtToken, err := auth.CreateAccessToken(user.ID, user.Username, 3600) + if err != nil { + return "", errors.New("系统内部错误") + } + + return jwtToken, nil +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..4b64d31 --- /dev/null +++ b/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "gin-admin/internal/core" + "gin-admin/pkg/logger" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 14:20 +// @Desc: 程序主入口 + +func main() { + logger.SetupLogger("app.log") + core.Start() +} diff --git a/pkg/encrypt/sha256.go b/pkg/encrypt/sha256.go new file mode 100644 index 0000000..ba2e343 --- /dev/null +++ b/pkg/encrypt/sha256.go @@ -0,0 +1,22 @@ +package encrypt + +import ( + "crypto/sha256" + "encoding/hex" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 17:15 +// @Desc: 计算Sha256哈希值 + +func Sha256String(text, salt string) string { + textBytes := []byte(text) + saltBytes := []byte(salt) + + hash := sha256.New() + hash.Write(textBytes) + hash.Write(saltBytes) + + return hex.EncodeToString(hash.Sum(nil)) +} diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go new file mode 100644 index 0000000..6530f13 --- /dev/null +++ b/pkg/logger/logger.go @@ -0,0 +1,66 @@ +package logger + +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "os" + "sync" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 14:53 +// @Desc: 日志器封装 + +var ( + sugar *zap.SugaredLogger + baseLogger *zap.Logger + initOnce sync.Once +) + +func SetupLogger(filename string) { + initOnce.Do(func() { + var syncers []zapcore.WriteSyncer + + syncers = append(syncers, zapcore.AddSync(os.Stdout)) + + if filename != "" { + f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err == nil { + syncers = append(syncers, zapcore.AddSync(f)) + } + } + + multi := zapcore.NewMultiWriteSyncer(syncers...) + + encCfg := zap.NewProductionEncoderConfig() + encCfg.TimeKey = "time" + encCfg.LevelKey = "level" + encCfg.CallerKey = "caller" + encCfg.EncodeTime = zapcore.ISO8601TimeEncoder + encCfg.EncodeLevel = zapcore.CapitalLevelEncoder + encCfg.EncodeCaller = zapcore.ShortCallerEncoder + + encoder := zapcore.NewConsoleEncoder(encCfg) + core := zapcore.NewCore(encoder, multi, zapcore.DebugLevel) + + baseLogger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) + sugar = baseLogger.Sugar() + }) +} + +func Close() { + if baseLogger != nil { + _ = baseLogger.Sync() + } +} + +func Debug(args ...any) { sugar.Debug(args...) } +func Info(args ...any) { sugar.Info(args...) } +func Warn(args ...any) { sugar.Warn(args...) } +func Error(args ...any) { sugar.Error(args...) } + +func Debugf(template string, args ...any) { sugar.Debugf(template, args...) } +func Infof(template string, args ...any) { sugar.Infof(template, args...) } +func Warnf(template string, args ...any) { sugar.Warnf(template, args...) } +func Errorf(template string, args ...any) { sugar.Errorf(template, args...) } From 327f02630ac344a5efa9d6783b1adf1eb24c8b47 Mon Sep 17 00:00:00 2001 From: yv1ing Date: Thu, 28 Aug 2025 17:44:20 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0jwt=E9=89=B4=E6=9D=83?= =?UTF-8?q?=E4=B8=AD=E9=97=B4=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/middleware/auth.go | 81 +++++++++++++++++++++++++ internal/router/router.go | 7 +++ internal/service/system/user_service.go | 4 +- {internal => pkg}/auth/jwt.go | 11 ++-- 4 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 internal/middleware/auth.go rename {internal => pkg}/auth/jwt.go (74%) diff --git a/internal/middleware/auth.go b/internal/middleware/auth.go new file mode 100644 index 0000000..3534e74 --- /dev/null +++ b/internal/middleware/auth.go @@ -0,0 +1,81 @@ +package middleware + +import ( + "errors" + "gin-admin/internal/core/config" + "gin-admin/pkg/auth" + "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v5" + "net/http" + "regexp" + "strings" + + systemmodel "gin-admin/internal/model/system" +) + +// @Author: yv1ing +// @Author: me@yvling.cn +// @Date: 2025/8/28 17:31 +// @Desc: 鉴权中间件 + +func extractBearerToken(c *gin.Context) string { + authorization := c.GetHeader("Authorization") + if authorization == "" { + return "" + } + + parts := strings.SplitN(authorization, " ", 2) + if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") || parts[1] == "" { + return "" + } + + return parts[1] +} + +func JwtMiddleware(whitelist []string) gin.HandlerFunc { + var whitelistRegex []*regexp.Regexp + for _, pattern := range whitelist { + re, err := regexp.Compile(pattern) + if err == nil { + whitelistRegex = append(whitelistRegex, re) + } + } + + return func(c *gin.Context) { + path := c.Request.URL.Path + for _, re := range whitelistRegex { + if re.MatchString(path) { + c.Next() + return + } + } + + tokenStr := extractBearerToken(c) + if tokenStr == "" { + c.AbortWithStatusJSON(http.StatusUnauthorized, systemmodel.Response{ + Code: http.StatusUnauthorized, + Info: "请求头Authorization非法或缺失", + }) + return + } + + claims, err := auth.ParseAccessToken(tokenStr, config.Config.SecretKey) + if err != nil { + if errors.Is(err, jwt.ErrTokenExpired) { + c.AbortWithStatusJSON(http.StatusUnauthorized, systemmodel.Response{ + Code: http.StatusUnauthorized, + Info: "Token已过期", + }) + } else { + c.AbortWithStatusJSON(http.StatusUnauthorized, systemmodel.Response{ + Code: http.StatusUnauthorized, + Info: "Token不合法", + }) + } + return + } + + c.Set("UID", claims.ID) + c.Next() + } +} diff --git a/internal/router/router.go b/internal/router/router.go index 33e23cd..a827ff3 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -1,6 +1,7 @@ package router import ( + "gin-admin/internal/middleware" "github.com/gin-gonic/gin" systemapi "gin-admin/internal/api/system" @@ -11,7 +12,13 @@ import ( // @Date: 2025/8/28 16:17 // @Desc: 路由注册入口 +var whitelist = []string{ + `^/api/sys/login$`, +} + func SetupRoutes(eng *gin.Engine) { + eng.Use(middleware.JwtMiddleware(whitelist)) + api := eng.Group("/api") /* 系统内置接口 */ diff --git a/internal/service/system/user_service.go b/internal/service/system/user_service.go index a6777f9..9d5b05c 100644 --- a/internal/service/system/user_service.go +++ b/internal/service/system/user_service.go @@ -2,9 +2,9 @@ package system import ( "errors" - "gin-admin/internal/auth" "gin-admin/internal/core/config" "gin-admin/internal/repository" + "gin-admin/pkg/auth" "gin-admin/pkg/encrypt" "gorm.io/gorm" @@ -31,7 +31,7 @@ func SysUserLogin(username, password string) (string, error) { return "", errors.New("用户已被禁用") } - jwtToken, err := auth.CreateAccessToken(user.ID, user.Username, 3600) + jwtToken, err := auth.CreateAccessToken(user.ID, user.Username, config.Config.SecretKey) if err != nil { return "", errors.New("系统内部错误") } diff --git a/internal/auth/jwt.go b/pkg/auth/jwt.go similarity index 74% rename from internal/auth/jwt.go rename to pkg/auth/jwt.go index 94331f6..098029d 100644 --- a/internal/auth/jwt.go +++ b/pkg/auth/jwt.go @@ -3,7 +3,6 @@ package auth import ( "errors" "fmt" - "gin-admin/internal/core/config" "github.com/golang-jwt/jwt/v5" "time" ) @@ -19,8 +18,8 @@ type AccessClaims struct { jwt.RegisteredClaims } -func CreateAccessToken(ID uint, username string, ttl time.Duration) (string, error) { - jwtSecret := []byte(config.Config.SecretKey) +func CreateAccessToken(ID uint, username string, secretKey string) (string, error) { + jwtSecret := []byte(secretKey) claims := AccessClaims{ ID: ID, @@ -28,7 +27,7 @@ func CreateAccessToken(ID uint, username string, ttl time.Duration) (string, err RegisteredClaims: jwt.RegisteredClaims{ Subject: "gin-admin", IssuedAt: jwt.NewNumericDate(time.Now()), - ExpiresAt: jwt.NewNumericDate(time.Now().Add(ttl)), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(12 * time.Hour)), ID: fmt.Sprintf("%d-%d", ID, time.Now().UnixNano()), }, } @@ -37,8 +36,8 @@ func CreateAccessToken(ID uint, username string, ttl time.Duration) (string, err return token.SignedString(jwtSecret) } -func ParseAccessToken(tokenStr string) (*AccessClaims, error) { - jwtSecret := []byte(config.Config.SecretKey) +func ParseAccessToken(tokenStr, secretKey string) (*AccessClaims, error) { + jwtSecret := []byte(secretKey) token, err := jwt.ParseWithClaims(tokenStr, &AccessClaims{}, func(token *jwt.Token) (interface{}, error) { return jwtSecret, nil }) From 1e08057cdaa0194d38fe6c22b08d7dcb87fb0579 Mon Sep 17 00:00:00 2001 From: yv1ing Date: Thu, 28 Aug 2025 17:51:50 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=88=9D=E5=A7=8B=E5=8C=96=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/core/initialize/database.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/internal/core/initialize/database.go b/internal/core/initialize/database.go index 296c211..0f17600 100644 --- a/internal/core/initialize/database.go +++ b/internal/core/initialize/database.go @@ -26,13 +26,22 @@ func dsn() string { ) } +func recreateTables(db *gorm.DB, models ...interface{}) error { + err := db.Migrator().DropTable(models...) + if err != nil { + return err + } + return db.AutoMigrate(models...) +} + func InitDatabase() error { db, err := gorm.Open(mysql.Open(dsn()), &gorm.Config{}) if err != nil { return err } - err = db.AutoMigrate( + err = recreateTables( + db, &systemmodel.User{}, )