diff --git a/Makefile b/Makefile index d2297c9..302d83d 100644 --- a/Makefile +++ b/Makefile @@ -16,4 +16,12 @@ dist: .PHONY: test test: - @go test -v ./... -cover \ No newline at end of file + @go test -v ./... -cover + +.PHONY: lint +lint: + @golangci-lint run + +.PHONY: proto +proto: + @buf generate \ No newline at end of file diff --git a/container/container.go b/container/container.go index f30e6c4..26749ba 100644 --- a/container/container.go +++ b/container/container.go @@ -2,6 +2,7 @@ package container import ( "context" + "log" "go.uber.org/dig" ) @@ -9,5 +10,7 @@ import ( var Container *dig.Container = dig.New() func init() { - Container.Provide(context.Background) + if err := Container.Provide(context.Background); err != nil { + log.Fatal(err) + } } diff --git a/golangci-lint.yaml b/golangci-lint.yaml new file mode 100644 index 0000000..2f6f7e6 --- /dev/null +++ b/golangci-lint.yaml @@ -0,0 +1,164 @@ +linters-settings: + forbidigo: + # Forbid the following identifiers (list of regexp). + # Default: ["^(fmt\\.Print(|f|ln)|print|println)$"] + forbid: + - ^print.*$ + - 'fmt\.Print.*' + # Optionally put comments at the end of the regex, surrounded by `(# )?` + # Escape any special characters. + - 'fmt\.Print.*(# Do not commit print statements\.)?' + # Exclude godoc examples from forbidigo checks. + # Default: true + # exclude_godoc_examples: false + gofumpt: + # Select the Go version to target. + # Default: "1.15" + # Deprecated: use the global `run.go` instead. + lang-version: "1.18" + # Module path which contains the source code being formatted. + # Default: "" + # Choose whether to use the extra rules. + # Default: false + govet: + check-shadowing: true + # enable: + # - fieldalignment + settings: + printf: + funcs: + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + golint: + min-confidence: 0 + gocyclo: + min-complexity: 32 + maligned: + suggest-new: true + dupl: + threshold: 100 + goconst: + min-len: 2 + min-occurrences: 2 + depguard: + list-type: blacklist + packages: + # logging is allowed only by logutils.Log, logrus + # is allowed to use only in logutils package + - github.com/sirupsen/logrus + misspell: + locale: US + lll: + line-length: 200 + goimports: + local-prefixes: git.gobies.org + gocritic: + enabled-tags: + - performance + - style + - experimental + disabled-checks: + - wrapperFunc + - yodaStyleExpr + - unnamedResult + # - dupImport # https://github.com/go-critic/go-critic/issues/845 + - commentedOutCode + - importShadow + - appendCombine + - ifElseChain + - typeAssertChain + - builtinShadow + gosec: + excludes: + - G404 + - G501 + - G401 + revive: + ignore-generated-header: true + severity: warning + rules: + - name: atomic + - name: line-length-limit + severity: error + arguments: [200] + +linters: + # enable: + # - errcheck + # - goimports + # - golint + # - govet + # - staticcheck + # - gocyclo + # - maligned + # - goconst + # - depguard + # - misspell + # - lll + # - gocritic + # disable-all: true + enable: + - gocritic + - gocyclo + - lll + - goconst + - misspell + - govet + - errcheck + - forbidigo + # - staticcheck + - unused + # - maligned + - gosimple + # - structcheck + # - varcheck + - ineffassign + # - deadcode + - typecheck + # - golint + - revive + - gosec + - unconvert + # - goimports + - depguard + - prealloc + # - scopelint + - whitespace + - revive + - nilnil + +run: + go: '1.18' + + # default concurrency is a available CPU number + concurrency: 20 + + # timeout for analysis, e.g. 30s, 5m, default is 1m + deadline: 10m + + # exit code when at least one issue was found, default is 1 + issues-exit-code: 1 + # include test files or not, default is true + tests: false + + skip-dirs: + - vendor/(passes) + # - third_party/(checker|passes) +golint: + # minimal confidence for issues, default is 0.8 + min-confidence: 0.5 +issues: + exclude-use-default: true + max-issues-per-linter: 10 + max-same-issues: 0 + # exclude: + # - EXC0002 + +# golangci.com configuration +# https://github.com/golangci/golangci/wiki/Configuration +# service: +# golangci-lint-version: 1.17.x # use the fixed version to not introduce new linters unexpectedly +# prepare: +# - echo "here I can run custom commands, but no preparation needed for this repo" \ No newline at end of file diff --git a/middleware/operation.go b/middleware/operation.go index 87cd1fe..6de67e3 100644 --- a/middleware/operation.go +++ b/middleware/operation.go @@ -1,7 +1,9 @@ package middleware import ( - "atom/utils" + "atom/database/models" + "atom/providers/jwt" + "atom/providers/log" "bytes" "encoding/json" "io" @@ -12,15 +14,10 @@ import ( "sync" "time" - "github.com/flipped-aurora/gin-vue-admin/server/global" - "github.com/flipped-aurora/gin-vue-admin/server/model/system" - "github.com/flipped-aurora/gva-plugins/email/service" "github.com/gin-gonic/gin" "go.uber.org/zap" ) -var operationRecordService = service.ServiceGroupApp.SystemServiceGroup.OperationRecordService - var respPool sync.Pool func init() { @@ -29,15 +26,15 @@ func init() { } } -func OperationRecord() gin.HandlerFunc { +func OperationRecord(jwt *jwt.JWT) gin.HandlerFunc { return func(c *gin.Context) { var body []byte - var userId int + var userId int64 if c.Request.Method != http.MethodGet { var err error body, err = io.ReadAll(c.Request.Body) if err != nil { - global.GVA_LOG.Error("read body from request error:", zap.Error(err)) + log.Error("read body from request error:", zap.Error(err)) } else { c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) } @@ -54,18 +51,18 @@ func OperationRecord() gin.HandlerFunc { } body, _ = json.Marshal(&m) } - claims, _ := utils.GetClaims(c) - if claims.ID != 0 { - userId = int(claims.ID) + claims, _ := jwt.GetClaims(c) + if claims.UserID != 0 { + userId = int64(claims.UserID) } else { id, err := strconv.Atoi(c.Request.Header.Get("x-user-id")) if err != nil { - userId = 0 + log.Error(err) } - userId = id + userId = int64(id) } - record := system.SysOperationRecord{ - Ip: c.ClientIP(), + record := models.SysOperationRecord{ + IP: c.ClientIP(), Method: c.Request.Method, Path: c.Request.URL.Path, Agent: c.Request.UserAgent(), @@ -80,7 +77,7 @@ func OperationRecord() gin.HandlerFunc { newBody := respPool.Get().([]byte) copy(newBody, record.Body) record.Body = string(newBody) - defer respPool.Put(newBody[:0]) + defer respPool.Put(&newBody) } } @@ -95,8 +92,8 @@ func OperationRecord() gin.HandlerFunc { latency := time.Since(now) record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String() - record.Status = c.Writer.Status() - record.Latency = latency + record.Status = int64(c.Writer.Status()) + record.Latency = int64(latency) record.Resp = writer.body.String() if strings.Contains(c.Writer.Header().Get("Pragma"), "public") || @@ -113,13 +110,13 @@ func OperationRecord() gin.HandlerFunc { newBody := respPool.Get().([]byte) copy(newBody, record.Resp) record.Body = string(newBody) - defer respPool.Put(newBody[:0]) + defer respPool.Put(&newBody) } } - if err := operationRecordService.CreateSysOperationRecord(record); err != nil { - global.GVA_LOG.Error("create operation record error:", zap.Error(err)) - } + // if err := operationRecordService.CreateSysOperationRecord(record); err != nil { + // log.Error("create operation record error:", zap.Error(err)) + // } } } diff --git a/providers/config/section_database.go b/providers/config/section_database.go index 7a2cc85..0049c25 100755 --- a/providers/config/section_database.go +++ b/providers/config/section_database.go @@ -67,7 +67,7 @@ type PostgreSQL struct { } func (m *PostgreSQL) EmptyDsn() string { - dsnTpl := "host=%s user=%s password=%s port=%s dbname=postgres sslmode=disable TimeZone=Asia/Shanghai" + dsnTpl := "host=%s user=%s password=%s port=%d dbname=postgres sslmode=disable TimeZone=Asia/Shanghai" return fmt.Sprintf(dsnTpl, m.Host, m.User, m.Password, m.Port) } diff --git a/providers/jwt/jwt.go b/providers/jwt/jwt.go index ff6c51e..72b4e6c 100644 --- a/providers/jwt/jwt.go +++ b/providers/jwt/jwt.go @@ -3,10 +3,11 @@ package jwt import ( "atom/container" "atom/providers/config" + "atom/providers/log" "errors" - "log" "time" + "github.com/gin-gonic/gin" jwt "github.com/golang-jwt/jwt/v4" uuid "github.com/satori/go.uuid" "golang.org/x/sync/singleflight" @@ -22,12 +23,12 @@ func init() { type CustomClaims struct { BaseClaims BufferTime int64 - jwt.StandardClaims + jwt.RegisteredClaims } type BaseClaims struct { UUID uuid.UUID - ID uint + UserID uint Username string NickName string AuthorityId uint @@ -59,10 +60,10 @@ func (j *JWT) CreateClaims(baseClaims BaseClaims) CustomClaims { claims := CustomClaims{ BaseClaims: baseClaims, BufferTime: int64(bf / time.Second), // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失 - StandardClaims: jwt.StandardClaims{ - NotBefore: time.Now().Unix() - 1000, // 签名生效时间 - ExpiresAt: time.Now().Add(ep).Unix(), // 过期时间 7天 配置文件 - Issuer: j.config.Http.JWT.Issuer, // 签名的发行者 + RegisteredClaims: jwt.RegisteredClaims{ + NotBefore: jwt.NewNumericDate(time.Now().Add(-time.Second * 10)), // 签名生效时间 + ExpiresAt: jwt.NewNumericDate(time.Now().Add(ep)), // 过期时间 7天 配置文件 + Issuer: j.config.Http.JWT.Issuer, // 签名的发行者 }, } return claims @@ -112,7 +113,67 @@ func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) { } } -// 解析 token -func (j *JWT) ParseCliam(claim string) (*CustomClaims, error) { - +func (j *JWT) GetClaims(c *gin.Context) (*CustomClaims, error) { + token := c.Request.Header.Get("x-token") + claims, err := j.ParseToken(token) + if err != nil { + log.Error("从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构") + } + return claims, err +} + +// GetUserID 从Gin的Context中获取从jwt解析出来的用户ID +func (j *JWT) GetUserID(c *gin.Context) uint { + if claims, exists := c.Get("claims"); !exists { + if cl, err := j.GetClaims(c); err != nil { + return 0 + } else { + return cl.UserID + } + } else { + waitUse := claims.(*CustomClaims) + return waitUse.UserID + } +} + +// GetUserUuid 从Gin的Context中获取从jwt解析出来的用户UUID +func (j *JWT) GetUserUuid(c *gin.Context) uuid.UUID { + if claims, exists := c.Get("claims"); !exists { + if cl, err := j.GetClaims(c); err != nil { + return uuid.UUID{} + } else { + return cl.UUID + } + } else { + waitUse := claims.(*CustomClaims) + return waitUse.UUID + } +} + +// GetUserAuthorityId 从Gin的Context中获取从jwt解析出来的用户角色id +func (j *JWT) GetUserAuthorityId(c *gin.Context) uint { + if claims, exists := c.Get("claims"); !exists { + if cl, err := j.GetClaims(c); err != nil { + return 0 + } else { + return cl.AuthorityId + } + } else { + waitUse := claims.(*CustomClaims) + return waitUse.AuthorityId + } +} + +// GetUserInfo 从Gin的Context中获取从jwt解析出来的用户角色id +func (j *JWT) GetUserInfo(c *gin.Context) *CustomClaims { + if claims, exists := c.Get("claims"); !exists { + if cl, err := j.GetClaims(c); err != nil { + return nil + } else { + return cl + } + } else { + waitUse := claims.(*CustomClaims) + return waitUse + } } diff --git a/providers/provider.go b/providers/provider.go index 88b0ebb..0b6c256 100644 --- a/providers/provider.go +++ b/providers/provider.go @@ -7,6 +7,5 @@ import ( _ "atom/providers/http" _ "atom/providers/jwt" _ "atom/providers/log" - _ "atom/providers/micro" _ "atom/providers/single_flight" ) diff --git a/providers/rpc/assets.go b/providers/rpc/assets.go deleted file mode 100644 index 909b04e..0000000 --- a/providers/rpc/assets.go +++ /dev/null @@ -1,20 +0,0 @@ -package rpc - -import ( - "log" - - "atom/container" - "atom/proto" - - "go-micro.dev/v4" -) - -func init() { - err := container.Container.Provide(func(svc micro.Service) proto.WebApiService { - return proto.NewWebApiService("web.api", svc.Client()) - }) - - if err != nil { - log.Fatal(err) - } -} diff --git a/utils/clamis.go b/utils/clamis.go deleted file mode 100644 index 3609914..0000000 --- a/utils/clamis.go +++ /dev/null @@ -1,75 +0,0 @@ -package utils - -import ( - "atom/providers/jwt" - - "github.com/flipped-aurora/gin-vue-admin/server/global" - "github.com/gin-gonic/gin" - uuid "github.com/satori/go.uuid" -) - -func GetClaims(c *gin.Context, jwt *jwt.JWT) (*jwt.CustomClaims, error) { - token := c.Request.Header.Get("x-token") - j := NewJWT() - claims, err := j.ParseToken(token) - if err != nil { - global.GVA_LOG.Error("从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构") - } - return claims, err -} - -// GetUserID 从Gin的Context中获取从jwt解析出来的用户ID -func GetUserID(c *gin.Context) uint { - if claims, exists := c.Get("claims"); !exists { - if cl, err := GetClaims(c); err != nil { - return 0 - } else { - return cl.ID - } - } else { - waitUse := claims.(*systemReq.CustomClaims) - return waitUse.ID - } -} - -// GetUserUuid 从Gin的Context中获取从jwt解析出来的用户UUID -func GetUserUuid(c *gin.Context) uuid.UUID { - if claims, exists := c.Get("claims"); !exists { - if cl, err := GetClaims(c); err != nil { - return uuid.UUID{} - } else { - return cl.UUID - } - } else { - waitUse := claims.(*systemReq.CustomClaims) - return waitUse.UUID - } -} - -// GetUserAuthorityId 从Gin的Context中获取从jwt解析出来的用户角色id -func GetUserAuthorityId(c *gin.Context) uint { - if claims, exists := c.Get("claims"); !exists { - if cl, err := GetClaims(c); err != nil { - return 0 - } else { - return cl.AuthorityId - } - } else { - waitUse := claims.(*systemReq.CustomClaims) - return waitUse.AuthorityId - } -} - -// GetUserInfo 从Gin的Context中获取从jwt解析出来的用户角色id -func GetUserInfo(c *gin.Context) *systemReq.CustomClaims { - if claims, exists := c.Get("claims"); !exists { - if cl, err := GetClaims(c); err != nil { - return nil - } else { - return cl - } - } else { - waitUse := claims.(*systemReq.CustomClaims) - return waitUse - } -} diff --git a/utils/zip.go b/utils/zip.go index e0075f4..69f8827 100644 --- a/utils/zip.go +++ b/utils/zip.go @@ -19,13 +19,15 @@ func Unzip(zipFile string, destDir string) ([]string, error) { defer zipReader.Close() for _, f := range zipReader.File { - if strings.Index(f.Name, "..") > -1 { + if strings.Contains(f.Name, "..") { return []string{}, fmt.Errorf("%s 文件名不合法", f.Name) } fpath := filepath.Join(destDir, f.Name) paths = append(paths, fpath) if f.FileInfo().IsDir() { - os.MkdirAll(fpath, os.ModePerm) + if err := os.MkdirAll(fpath, os.ModePerm); err != nil { + return nil, err + } } else { if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { return []string{}, err