liujiandao
2024-02-29 1e7ef4a6705d59f7f3308638d44cc3b0cf340211
登录与生丝定价
6个文件已添加
7个文件已修改
402 ■■■■ 已修改文件
constvar/const.go 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/raw_silk_standard.go 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/request/raw_silk_standard_request.go 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
extend/code/code.go 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.mod 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.sum 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
middleware/jwt.go 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
middleware/jwt_request.go 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
middleware/reset_pwd.go 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
middleware/utils.go 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/raw_silk_price_standard.go 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/ecode/code.go 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
router/router.go 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
constvar/const.go
@@ -8,3 +8,11 @@
    DictTypeColor                    //颜色
    DictTypeSpec                     //规格
)
type UserType int
const (
    UserTypeSuper   UserType = iota + 1 // 超级管理员
    UserTypePrimary                     // 主账户
    UserTypeSub                         // 子账户
)
controllers/raw_silk_standard.go
New file
@@ -0,0 +1,62 @@
package controllers
import (
    "github.com/gin-gonic/gin"
    "silkserver/controllers/request"
    "silkserver/extend/code"
    "silkserver/extend/util"
    "silkserver/models"
)
type RawSilkStandardController struct {
}
// SavePriceStandard
//
//    @Tags        系统设置/生丝定价标准
//    @Summary    保存生丝定价标准
//    @Produce    application/json
//    @Param        object    body        models.RawSilkPriceStandard    true    "参数"
//    @Success    200        {object}    util.Response        "成功"
//    @Router        /api-jl/v1/system/savePriceStandard [post]
func (slf RawSilkStandardController) SavePriceStandard(c *gin.Context) {
    var priceStandard models.RawSilkPriceStandard
    err := c.BindJSON(&priceStandard)
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
        return
    }
    if priceStandard.ID > 0 {
        err = models.NewRawSilkPriceStandardSearch().Save(&priceStandard)
    } else {
        err = models.NewRawSilkPriceStandardSearch().Create(&priceStandard)
    }
    if err != nil {
        util.ResponseFormat(c, code.SaveFail, "保存失败")
        return
    }
    util.ResponseFormat(c, code.Success, "保存成功")
}
// GetPriceStandardList
//
//    @Tags        系统设置/生丝定价标准
//    @Summary    获取生丝定价标准
//    @Produce    application/json
//    @Param        object    body        models.RawSilkPriceStandard    true    "参数"
//    @Success    200        {object}    util.Response        "成功"
//    @Router        /api-jl/v1/system/getPriceStandardList [get]
func (slf RawSilkStandardController) GetPriceStandardList(c *gin.Context) {
    var param request.GetPriceStandard
    err := c.BindJSON(&param)
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
        return
    }
    list, total, err := models.NewRawSilkPriceStandardSearch().SetPage(param.Page, param.PageSize).Find()
    if err != nil {
        util.ResponseFormat(c, code.SelectError, "查询失败")
        return
    }
    util.ResponseFormatList(c, code.Success, list, int(total))
}
controllers/request/raw_silk_standard_request.go
New file
@@ -0,0 +1,6 @@
package request
type GetPriceStandard struct {
    PageInfo
    KeyWord string `json:"keyWord"`
}
extend/code/code.go
@@ -25,4 +25,5 @@
    NoTemplateError              = &Code{3010, "未配置订单模板"}
    InternalError                = &Code{3011, "内部错误"}
    NoProductionRequiredError    = &Code{3012, "当前库存满足毛需求量,暂时无需进行生产"}
    SelectError                  = &Code{3013, "查询失败"}
)
go.mod
@@ -6,7 +6,9 @@
    basic.com/aps/nsqclient.git v0.0.0-20230517072415-37491f4a5d25
    github.com/dgrijalva/jwt-go v3.2.0+incompatible
    github.com/gin-gonic/gin v1.9.1
    github.com/golang-jwt/jwt/v4 v4.5.0
    github.com/nsqio/go-nsq v1.1.0
    github.com/shopspring/decimal v1.3.1
    github.com/spf13/viper v1.18.2
    github.com/swaggo/files v1.0.1
    github.com/swaggo/gin-swagger v1.6.0
go.sum
@@ -50,6 +50,8 @@
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@@ -109,6 +111,8 @@
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
middleware/jwt.go
@@ -1,94 +1,39 @@
package middleware
import (
    "errors"
    "fmt"
    "silkserver/conf"
    "strings"
    "time"
    jwt "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "silkserver/extend/util"
    "silkserver/pkg/contextx"
    "silkserver/pkg/ecode"
    "strings"
)
func validateToken(tokenString string) (util.JSON, error) {
    secretKey := []byte(conf.WebConf.JWTSecret)
    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        // Don't forget to validate the alg is what you expect:
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
        }
        return secretKey, nil
    })
    if err != nil {
        return util.JSON{}, err
    }
    if !token.Valid {
        return util.JSON{}, errors.New("invalid token")
    }
    return token.Claims.(jwt.MapClaims), nil
}
// JWTMiddleware parses JWT token from cookie and stores data and expires date to the context
// JWT Token can be passed as cookie, or Authorization header
func JWTMiddleware() gin.HandlerFunc {
func JWTAuth() gin.HandlerFunc {
    return func(c *gin.Context) {
        tokenString, err := c.Cookie("token")
        // failed to read cookie
        if err != nil {
            // try reading HTTP Header
            authorization := c.Request.Header.Get("Authorization")
            if authorization == "" {
                c.Next()
                return
            }
            sp := strings.Split(authorization, "Bearer ")
            // invalid token
            if len(sp) < 1 {
                c.Next()
                return
            }
            tokenString = sp[1]
        ctx := new(contextx.Context).SetCtx(c)
        // 我们这里jwt鉴权取头部信息 Authorization 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
        token := c.Request.Header.Get("Authorization")
        if token == "" {
            ctx.Fail(ecode.JWTEmpty)
            c.Abort()
            return
        }
        tokenData, err := validateToken(tokenString)
        slices := strings.Split(token, " ")
        if len(slices) == 2 {
            token = slices[1]
        }
        j := NewJWT()
        // parseToken 解析token包含的信息
        claims, err := j.ParseToken(token)
        if err != nil {
            fmt.Println(err.Error())
            if err == TokenExpired {
                c.Next()
                return
            }
            c.Next()
            return
        }
        userParentId := tokenData["parentId"].(string)
        if userParentId == conf.WebConf.NodeId {
            c.Set("parentId", userParentId)
        } else {
            c.Next()
            return
        }
        c.Set("token_expire", tokenData["exp"])
        c.Set("claims", claims)
        c.Next()
    }
}
func GenerateToken(data interface{}) (string, error) {
    //  token is valid for 1 hour
    date := time.Now().Add(time.Hour * 12)
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "user": data,
        "exp":  date.Unix(),
    })
    secretKey := []byte(conf.WebConf.JWTSecret)
    tokenString, err := token.SignedString(secretKey)
    return tokenString, err
}
middleware/jwt_request.go
New file
@@ -0,0 +1,21 @@
package middleware
import (
    "github.com/dgrijalva/jwt-go"
    "silkserver/constvar"
)
// Custom claims structure
type CustomClaims struct {
    BaseClaims
    BufferTime int64
    jwt.StandardClaims
}
type BaseClaims struct {
    UserId      string
    Username    string
    ParentId    string
    UserType    constvar.UserType
    ModifiedPwd *bool
}
middleware/reset_pwd.go
New file
@@ -0,0 +1,30 @@
package middleware
import (
    "github.com/gin-gonic/gin"
    "silkserver/pkg/contextx"
    "silkserver/pkg/ecode"
)
func VerifyResetPwd() gin.HandlerFunc {
    return func(c *gin.Context) {
        ctx := new(contextx.Context).SetCtx(c)
        params, ok := c.Get("claims")
        if !ok {
            c.Abort()
            return
        }
        claims := params.(*CustomClaims)
        if claims.ModifiedPwd == nil { //兼容没有ModifiedPwd值的token
            ctx.Fail(ecode.JWTExpire)
            c.Abort()
            return
        }
        if !*claims.ModifiedPwd {
            ctx.Fail(ecode.ResetPwd)
            c.Abort()
            return
        }
    }
}
middleware/utils.go
New file
@@ -0,0 +1,68 @@
package middleware
import (
    "errors"
    "github.com/gin-gonic/gin"
    "github.com/golang-jwt/jwt/v4"
)
type JWT struct {
    SigningKey []byte
}
var (
    TokenExpired     = errors.New("Token is expired")
    TokenNotValidYet = errors.New("Token not active yet")
    TokenMalformed   = errors.New("That's not even a token")
    TokenInvalid     = errors.New("Couldn't handle this token:")
)
func NewJWT() *JWT {
    return &JWT{
        []byte("327a9457-899a-481e-8b30-58cc97e5b808"),
    }
}
// CreateToken 创建一个token
func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(j.SigningKey)
}
// ParseToken 解析token
func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) {
    token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
        return j.SigningKey, nil
    })
    if err != nil {
        if ve, ok := err.(*jwt.ValidationError); ok {
            if ve.Errors&jwt.ValidationErrorMalformed != 0 {
                return nil, TokenMalformed
            } else if ve.Errors&jwt.ValidationErrorExpired != 0 {
                // Token is expired
                return nil, TokenExpired
            } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
                return nil, TokenNotValidYet
            } else {
                return nil, TokenInvalid
            }
        }
    }
    if token != nil {
        if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
            return claims, nil
        }
        return nil, TokenInvalid
    } else {
        return nil, TokenInvalid
    }
}
func GetUserInfo(c *gin.Context) *CustomClaims {
    if claims, exists := c.Get("claims"); exists {
        waitUse := claims.(*CustomClaims)
        return waitUse
    }
    return nil
}
models/raw_silk_price_standard.go
New file
@@ -0,0 +1,96 @@
package models
import (
    "fmt"
    "github.com/shopspring/decimal"
    "gorm.io/gorm"
    "silkserver/pkg/mysqlx"
)
// RawSilkPriceStandard
type (
    RawSilkPriceStandard struct {
        gorm.Model
        MarketNumber       string          `json:"marketNumber" gorm:"type:varchar(255);comment:庄口编号"`
        RawSilkGradeNumber string          `json:"rawSilkGradeNumber" gorm:"type:varchar(255);comment:生丝等级编号"`
        PayStandard        decimal.Decimal `json:"payStandard" gorm:"type:decimal(20,3);comment:薪酬标准"`
        Unit               string          `json:"unit" gorm:"type:varchar(100);comment:单位"`
        Notes              string          `json:"notes" gorm:"type:varchar(255);comment:备注"`
    }
    RawSilkPriceStandardSearch struct {
        RawSilkPriceStandard
        Order    string
        PageNum  int
        PageSize int
        Orm      *gorm.DB
    }
)
func (slf RawSilkPriceStandard) TableName() string {
    return "raw_silk_price_standard"
}
func NewRawSilkPriceStandardSearch() *RawSilkPriceStandardSearch {
    return &RawSilkPriceStandardSearch{Orm: mysqlx.GetDB()}
}
func (slf *RawSilkPriceStandardSearch) SetOrm(tx *gorm.DB) *RawSilkPriceStandardSearch {
    slf.Orm = tx
    return slf
}
func (slf *RawSilkPriceStandardSearch) SetPage(page, size int) *RawSilkPriceStandardSearch {
    slf.PageNum, slf.PageSize = page, size
    return slf
}
func (slf *RawSilkPriceStandardSearch) SetOrder(order string) *RawSilkPriceStandardSearch {
    slf.Order = order
    return slf
}
func (slf *RawSilkPriceStandardSearch) build() *gorm.DB {
    db := slf.Orm.Table(slf.TableName())
    return db
}
// Create 单条插入
func (slf *RawSilkPriceStandardSearch) Create(record *RawSilkPriceStandard) error {
    db := slf.build()
    err := db.Create(record).Error
    if err != nil {
        return fmt.Errorf("create err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *RawSilkPriceStandardSearch) Find() ([]*RawSilkPriceStandard, int64, error) {
    var (
        records = make([]*RawSilkPriceStandard, 0)
        total   int64
        db      = slf.build()
    )
    if err := db.Count(&total).Error; err != nil {
        return records, total, fmt.Errorf("find count err: %v", err)
    }
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, total, fmt.Errorf("find records err: %v", err)
    }
    return records, total, nil
}
func (slf *RawSilkPriceStandardSearch) Save(record *RawSilkPriceStandard) error {
    var db = slf.build()
    if err := db.Save(record).Error; err != nil {
        return fmt.Errorf("save err: %v, record: %+v", err, record)
    }
    return nil
}
pkg/ecode/code.go
@@ -18,4 +18,5 @@
    JWTEmpty              = 2013 // JWT为空
    JWTExpire             = 2014 // JWT过期
    JWTParseErr           = 2015 // JWT解析失败
    ResetPwd              = 2036 //账号设置密码
)
router/router.go
@@ -18,6 +18,8 @@
    r.StaticFS(conf.LocalConf.StorePath, http.Dir(conf.LocalConf.StorePath)) // 为用户头像和文件提供静态地址
    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    r.Use(middleware.JWTAuth())
    r.Use(middleware.VerifyResetPwd())
    urlPrefix := "/api-jl/v1"