zhangqian
2024-03-23 b68185aed1a86536b01fdfbca6b2cca7bd71a50f
增加token验证和数据权限过滤
2个文件已添加
6个文件已修改
332 ■■■■ 已修改文件
conf/config.go 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
conf/config.yaml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/order.go 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
middleware/jwt.go 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/outsourcing_order.go 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
router/router.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/jwt/claims.go 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/jwt/jwt.go 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
conf/config.go
@@ -23,14 +23,14 @@
type (
    webConf struct {
        Host      string // 本机ip地址
        Port      string // 端口号
        APPort    string // 本机作为的Grpc服务端的端口号
        AlHost    string // 算法服务ip地址
        AlPort    string // 算法服务端口号
        NodeId    string // 主账户用户名
        OssType   string // 对象存储类型
        JWTSecret string
        Host    string // 本机ip地址
        Port    string // 端口号
        APPort  string // 本机作为的Grpc服务端的端口号
        AlHost  string // 算法服务ip地址
        AlPort  string // 算法服务端口号
        NodeId  string // 主账户用户名
        OssType string // 对象存储类型
        JWTKey  string
    }
    nsqConf struct {
conf/config.yaml
@@ -1,6 +1,7 @@
web:
  port: 8008
  host: 192.168.20.119
  jwtKey: 12345
service:
  aps: 192.168.20.120:9091
db:
controllers/order.go
@@ -13,6 +13,7 @@
    "outsourcing/request"
    "outsourcing/service"
    "outsourcing/service/outsourcing"
    "outsourcing/utils/jwt"
)
type OrderController struct{}
@@ -30,7 +31,14 @@
        util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
        return
    }
    list, total, err := models.NewOutsourcingOrderSearch().SetPage(params.Page, params.PageSize).SetKeyword(params.Keyword).SetOrder("id desc").Find()
    companyId := jwt.GetCompanyID(c)
    if companyId == 0 {
        util.ResponseFormat(c, code.InternalError, "内部错误")
        return
    }
    list, total, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(companyId).SetPage(params.Page, params.PageSize).SetKeyword(params.Keyword).SetOrder("id desc").Find()
    if err != nil {
        util.ResponseFormat(c, code.InternalError, "查询错误")
        return
@@ -45,7 +53,7 @@
// @Success   200   {object}  util.ResponseList{data=request.OutsourcingOrderOverview}  "成功"
// @Router    /api-outsourcing/v1/order/overview [get]
func (slf *OrderController) OrderOverview(c *gin.Context) {
    result, err := models.NewOutsourcingOrderSearch().CountGroupByStatus()
    result, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(jwt.GetCompanyID(c)).CountGroupByStatus()
    if err != nil {
        util.ResponseFormat(c, code.InternalError, "查询错误")
        return
@@ -80,6 +88,13 @@
        util.ResponseFormat(c, code.RequestParamError, "参数缺失")
        return
    }
    _, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(jwt.GetCompanyID(c)).SetID(params.OutsourcingOrderId).First()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "订单不存在")
        return
    }
    list, total, err := models.NewOutsourcingOrderProductSearch().SetPage(params.Page, params.PageSize).SetOutsourcingOrderID(params.OutsourcingOrderId).SetOrder("id desc").Find()
    if err != nil {
        util.ResponseFormat(c, code.InternalError, "查询错误")
@@ -105,8 +120,15 @@
        util.ResponseFormat(c, code.RequestParamError, "物料申请不能为空")
        return
    }
    _, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(jwt.GetCompanyID(c)).SetNumber(params.ApplyList[0].OutsourcingOrderNumber).First()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "订单不存在")
        return
    }
    var apply []*models.OutsourcingMaterialApply
    err := structx.AssignTo(params.ApplyList, &apply)
    err = structx.AssignTo(params.ApplyList, &apply)
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "数据转换失败")
        return
@@ -141,6 +163,13 @@
        util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
        return
    }
    _, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(jwt.GetCompanyID(c)).SetNumber(params.Number).First()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "订单不存在")
        return
    }
    find, err := models.NewOutsourcingMaterialApplySearch().SetOutsourcingOrderNumber(params.Number).FindNotTotal()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "查询失败")
@@ -162,6 +191,13 @@
        util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
        return
    }
    _, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(jwt.GetCompanyID(c)).SetNumber(params.OutsourcingOrderNumber).First()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "订单不存在")
        return
    }
    //限定状态参数
    if params.Status == constvar.OutsourcingOrderStatusCreate || //取消确认
        params.Status == constvar.OutsourcingOrderStatusWaitProduce || //确认接受
@@ -196,6 +232,12 @@
    }
    if params.OutsourcingOrderID == 0 {
        util.ResponseFormat(c, code.RequestParamError, "参数缺失")
        return
    }
    _, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(jwt.GetCompanyID(c)).SetID(params.OutsourcingOrderID).First()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "订单不存在")
        return
    }
@@ -236,6 +278,13 @@
        util.ResponseFormat(c, code.RequestParamError, "参数缺失")
        return
    }
    _, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(jwt.GetCompanyID(c)).SetID(params.OutsourcingOrderID).First()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "订单不存在")
        return
    }
    if len(params.DeliveryList) == 0 {
        util.ResponseFormat(c, code.RequestParamError, "发货列表不能为空")
        return
@@ -248,8 +297,8 @@
        WaybillNumber:      params.WaybillNumber,
    }
    err := models.WithTransaction(func(db *gorm.DB) error {
        err := models.NewOutsourcingOrderDeliverySearch().SetOrm(db).Create(delivery)
    err = models.WithTransaction(func(db *gorm.DB) error {
        err = models.NewOutsourcingOrderDeliverySearch().SetOrm(db).Create(delivery)
        if err != nil {
            return err
        }
@@ -285,6 +334,13 @@
        util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
        return
    }
    _, err := models.NewOutsourcingOrderSearch().SetEnterpriseID(jwt.GetCompanyID(c)).SetID(params.OutsourcingOrderID).First()
    if err != nil {
        util.ResponseFormat(c, code.RequestParamError, "订单不存在")
        return
    }
    list, err := models.NewOutsourcingOrderDeliveryDetailsSearch().
        SetOutsourcingOrderID(params.OutsourcingOrderID).
        SetPreload(true).
middleware/jwt.go
@@ -1,94 +1,47 @@
package middleware
import (
    "errors"
    "fmt"
    "outsourcing/conf"
    "strings"
    "time"
    jwt "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "outsourcing/extend/util"
    "outsourcing/conf"
    "outsourcing/pkg/contextx"
    "outsourcing/pkg/ecode"
    "outsourcing/utils/jwt"
    "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]
        }
        tokenData, err := validateToken(tokenString)
        if err != nil {
            fmt.Println(err.Error())
            c.Next()
        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
        }
        userParentId := tokenData["parentId"].(string)
        if userParentId == conf.WebConf.NodeId {
            c.Set("parentId", userParentId)
        } else {
            c.Next()
        slices := strings.Split(token, " ")
        if len(slices) == 2 {
            token = slices[1]
        }
        j := jwt.NewOutsideJWT(conf.WebConf.JWTKey)
        // parseToken 解析token包含的信息
        claims, err := j.ParseToken(token)
        if err != nil {
            if err == jwt.TokenExpired {
                ctx.Fail(ecode.JWTExpire)
                c.Abort()
                return
            }
            ctx.Fail(ecode.JWTParseErr)
            c.Abort()
            return
        }
        c.Set("token_expire", tokenData["exp"])
        if claims.CompanyId == 0 {
            ctx.Fail(ecode.JWTExpire)
            c.Abort()
            return
        }
        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
}
models/outsourcing_order.go
@@ -65,6 +65,11 @@
    return slf
}
func (slf *OutsourcingOrderSearch) SetEnterpriseID(id uint) *OutsourcingOrderSearch {
    slf.EnterpriseID = id
    return slf
}
func (slf *OutsourcingOrderSearch) SetIDs(ids []uint) *OutsourcingOrderSearch {
    slf.IDs = ids
    return slf
@@ -96,6 +101,10 @@
        db = db.Where("id = ?", slf.ID)
    }
    if slf.EnterpriseID != 0 {
        db = db.Where("enterprise_id = ?", slf.EnterpriseID)
    }
    if len(slf.IDs) != 0 {
        db = db.Where("id in ?", slf.IDs)
    }
router/router.go
@@ -22,7 +22,7 @@
    urlPrefix := "/api-outsourcing/v1"
    outsourcingApi := new(controllers.OrderController)
    outsourcingGroup := r.Group(urlPrefix + "/order")
    outsourcingGroup := r.Group(urlPrefix + "/order").Use(middleware.JWTAuth())
    {
        outsourcingGroup.GET("list", outsourcingApi.OutsourcingOrderList)                  // 委外订单列表
        outsourcingGroup.GET("overview", outsourcingApi.OrderOverview)                     // 委外订单统计
utils/jwt/claims.go
New file
@@ -0,0 +1,62 @@
package jwt
import (
    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "outsourcing/conf"
    "outsourcing/pkg/logx"
    "strings"
)
type OutsideUserClaims struct {
    UserId      string
    Username    string
    ParentId    string
    CompanyId   uint
    CompanyName string
    BufferTime  int64
    jwt.StandardClaims
}
func GetClaims(c *gin.Context) (*OutsideUserClaims, error) {
    token := c.Request.Header.Get("Authorization")
    logx.Infof("GetClaims token:%v", token)
    slices := strings.Split(token, " ")
    if len(slices) == 2 {
        token = slices[1]
    }
    j := NewOutsideJWT(conf.WebConf.JWTKey)
    claims, err := j.ParseToken(token)
    if err != nil {
        logx.Error("从Gin的Context中获取从jwt解析信息失败, 请检查请求头是否存在x-token且claims是否为规定结构")
    }
    return claims, err
}
// GetCompanyID 从Gin的Context中获取从jwt解析出来的公司ID
func GetCompanyID(c *gin.Context) uint {
    if claims, exists := c.Get("claims"); !exists {
        if cl, err := GetClaims(c); err != nil {
            return 0
        } else {
            return cl.CompanyId
        }
    } else {
        waitUse := claims.(*OutsideUserClaims)
        return waitUse.CompanyId
    }
}
// GetUserInfo 从Gin的Context中获取从jwt解析出来的用户信息
func GetUserInfo(c *gin.Context) *OutsideUserClaims {
    if claims, exists := c.Get("claims"); !exists {
        if cl, err := GetClaims(c); err != nil {
            return nil
        } else {
            return cl
        }
    } else {
        waitUse := claims.(*OutsideUserClaims)
        return waitUse
    }
}
utils/jwt/jwt.go
New file
@@ -0,0 +1,63 @@
package jwt
import (
    "errors"
    "github.com/dgrijalva/jwt-go"
)
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:")
)
type OutSideJWT struct {
    SigningKey []byte
}
func NewOutsideJWT(signKey string) *OutSideJWT {
    return &OutSideJWT{
        []byte(signKey),
    }
}
// CreateToken 创建一个token
func (j *OutSideJWT) CreateToken(claims OutsideUserClaims) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(j.SigningKey)
}
// ParseToken 解析token
func (j *OutSideJWT) ParseToken(tokenString string) (*OutsideUserClaims, error) {
    token, err := jwt.ParseWithClaims(tokenString, &OutsideUserClaims{}, 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.(*OutsideUserClaims); ok && token.Valid {
            return claims, nil
        }
        return nil, TokenInvalid
    } else {
        return nil, TokenInvalid
    }
}