|
@@ -0,0 +1,325 @@
|
|
|
+package common
|
|
|
+
|
|
|
+import (
|
|
|
+ "crypto/hmac"
|
|
|
+ "crypto/md5"
|
|
|
+ "crypto/sha256"
|
|
|
+ "designs/config"
|
|
|
+ "designs/global"
|
|
|
+ "encoding/hex"
|
|
|
+ "encoding/json"
|
|
|
+ "errors"
|
|
|
+ "fmt"
|
|
|
+ "math/rand"
|
|
|
+ "net/http"
|
|
|
+ "net/url"
|
|
|
+ "sort"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/gin-gonic/gin"
|
|
|
+ "github.com/golang-jwt/jwt/v5"
|
|
|
+)
|
|
|
+
|
|
|
+// 打印
|
|
|
+func Print(i interface{}) {
|
|
|
+ fmt.Println("---")
|
|
|
+ fmt.Println(i)
|
|
|
+ fmt.Println("---")
|
|
|
+}
|
|
|
+
|
|
|
+// 返回JSON
|
|
|
+func RetJson(code int, msg string, data interface{}, c *gin.Context) {
|
|
|
+ c.JSON(http.StatusOK, gin.H{
|
|
|
+ "code": code,
|
|
|
+ "msg": msg,
|
|
|
+ "data": data,
|
|
|
+ "timestamp": GetTimeUnix(),
|
|
|
+ })
|
|
|
+ c.Abort()
|
|
|
+}
|
|
|
+
|
|
|
+// 获取当前时间戳
|
|
|
+func GetTimeUnix() int64 {
|
|
|
+ return time.Now().Unix()
|
|
|
+}
|
|
|
+
|
|
|
+// MD5 方法
|
|
|
+func MD5(str string) string {
|
|
|
+ s := md5.New()
|
|
|
+ s.Write([]byte(str))
|
|
|
+ return hex.EncodeToString(s.Sum(nil))
|
|
|
+}
|
|
|
+
|
|
|
+// 生成签名
|
|
|
+func CreateSign(params url.Values) string {
|
|
|
+ var key []string
|
|
|
+ var str = ""
|
|
|
+ for k := range params {
|
|
|
+ if k != "sn" {
|
|
|
+ key = append(key, k)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ sort.Strings(key)
|
|
|
+ for i := 0; i < len(key); i++ {
|
|
|
+ if i == 0 {
|
|
|
+ str = fmt.Sprintf("%v=%v", key[i], params.Get(key[i]))
|
|
|
+ } else {
|
|
|
+ str = str + fmt.Sprintf("&%v=%v", key[i], params.Get(key[i]))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 自定义签名算法
|
|
|
+ sign := MD5(MD5(str) + MD5(config.Get("app_name")+config.Get("app_secret")))
|
|
|
+ return sign
|
|
|
+}
|
|
|
+
|
|
|
+// 验证签名
|
|
|
+func VerifySign(c *gin.Context) {
|
|
|
+ var method = c.Request.Method
|
|
|
+ var ts int64
|
|
|
+ var sn string
|
|
|
+ var req url.Values
|
|
|
+
|
|
|
+ if method == "GET" {
|
|
|
+ req = c.Request.URL.Query()
|
|
|
+ sn = c.Query("sn")
|
|
|
+ ts, _ = strconv.ParseInt(c.Query("ts"), 10, 64)
|
|
|
+
|
|
|
+ } else if method == "POST" {
|
|
|
+ c.Request.ParseForm()
|
|
|
+ req = c.Request.PostForm
|
|
|
+ sn = c.PostForm("sn")
|
|
|
+ ts, _ = strconv.ParseInt(c.PostForm("ts"), 10, 64)
|
|
|
+ } else {
|
|
|
+ RetJson(500, "Illegal requests", "", c)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ exp, _ := strconv.ParseInt(config.Get("api_expire"), 10, 64)
|
|
|
+
|
|
|
+ // 验证过期时间
|
|
|
+ if ts > GetTimeUnix() || GetTimeUnix()-ts >= exp {
|
|
|
+ RetJson(500, "Ts Error", "", c)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证签名
|
|
|
+ if sn == "" || sn != CreateSign(req) {
|
|
|
+ RetJson(500, "Sn Error", "", c)
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func StructToArr(data interface{}) (string, error) {
|
|
|
+ res, err := json.Marshal(data)
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ //将json解析为map
|
|
|
+ var mapdata map[string]interface{}
|
|
|
+ err1 := json.Unmarshal([]byte(res), &mapdata)
|
|
|
+ if err1 != nil {
|
|
|
+ return "", err1
|
|
|
+ }
|
|
|
+ //获取排序map键值
|
|
|
+ keys := make([]string, 0, len(mapdata))
|
|
|
+ for key := range mapdata {
|
|
|
+ keys = append(keys, key)
|
|
|
+ }
|
|
|
+ //排序
|
|
|
+ sort.Strings(keys)
|
|
|
+ fmt.Println("我的数据:", string(res))
|
|
|
+ //排序后直接构建map
|
|
|
+ sortMap := make(map[string]interface{}, len(mapdata))
|
|
|
+ for _, key := range keys {
|
|
|
+ sortMap[key] = mapdata[key]
|
|
|
+ }
|
|
|
+ //序列化
|
|
|
+ sortJosn, err2 := json.Marshal(sortMap)
|
|
|
+ if err2 != nil {
|
|
|
+ return "", err2
|
|
|
+ }
|
|
|
+ return string(sortJosn), nil
|
|
|
+}
|
|
|
+
|
|
|
+/* 检测数据是否篡改 */
|
|
|
+func VerifySignData(data interface{}) bool {
|
|
|
+ var checkSign string
|
|
|
+ var sign string = "test"
|
|
|
+ checkKey := "secret"
|
|
|
+
|
|
|
+ res, err := json.Marshal(data)
|
|
|
+ if err != nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ //将json解析为map
|
|
|
+ var mapdata map[string]interface{}
|
|
|
+ err1 := json.Unmarshal([]byte(res), &mapdata)
|
|
|
+ if err1 != nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ //fmt.Println("解析后的数据:", mapdata)
|
|
|
+
|
|
|
+ val, exist := mapdata[checkKey].(string)
|
|
|
+ if exist {
|
|
|
+ checkSign = val
|
|
|
+ } else {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ fmt.Println("解析后的数据:", mapdata)
|
|
|
+ //获取排序map键值
|
|
|
+ keys := make([]string, 0, len(mapdata))
|
|
|
+ for key := range mapdata {
|
|
|
+ if key != checkKey {
|
|
|
+ keys = append(keys, key)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // fmt.Println("解析后的keys数据:", keys)
|
|
|
+ //排序
|
|
|
+ sort.Strings(keys)
|
|
|
+ //排序后直接构建map
|
|
|
+ sortMap := make(map[string]interface{}, len(mapdata))
|
|
|
+ for _, key := range keys {
|
|
|
+ newKey := strings.ToLower(string(key[0])) + key[1:]
|
|
|
+ sortMap[newKey] = mapdata[key]
|
|
|
+ }
|
|
|
+ //序列化数据
|
|
|
+ sortJosn, err2 := json.Marshal(sortMap)
|
|
|
+ if err2 != nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ // fmt.Println("我的排序数据:", string(sortJosn), sign)
|
|
|
+
|
|
|
+ // sum := ([]byte("hello world"))
|
|
|
+ // fmt.Printf("加密数据:%x\n", sum)
|
|
|
+ // 密钥
|
|
|
+ key := []byte(config.Get("app.app_check_secret"))
|
|
|
+ // 数据
|
|
|
+ // data := []byte(msg)
|
|
|
+ // 创建一个新的HMAC将SHA-256用作哈希函数
|
|
|
+ h := hmac.New(sha256.New, key)
|
|
|
+ // 写入数据
|
|
|
+ h.Write(sortJosn)
|
|
|
+ // 得到MAC
|
|
|
+ mac := h.Sum(nil)
|
|
|
+ sign = hex.EncodeToString(mac)
|
|
|
+ // 打印MAC
|
|
|
+ fmt.Println("生成的签名:", sign, checkSign)
|
|
|
+
|
|
|
+ if sign != checkSign {
|
|
|
+ global.App.Log.Error("mapdata:", mapdata)
|
|
|
+ global.App.Log.Error("sign:", sign)
|
|
|
+ global.App.Log.Error("checkSign:", checkSign)
|
|
|
+ }
|
|
|
+
|
|
|
+ return sign == checkSign
|
|
|
+}
|
|
|
+
|
|
|
+// 生成token
|
|
|
+func GetDefineToken(openid string) string {
|
|
|
+ timestamp := time.Now().UnixNano() / int64(time.Millisecond)
|
|
|
+ randNum := 10000 + rand.Intn(10000)
|
|
|
+ token := fmt.Sprintf("%s%d%d", openid, timestamp, randNum)
|
|
|
+ return MD5(token)
|
|
|
+}
|
|
|
+
|
|
|
+// 自定义结构体
|
|
|
+type MyCustomClaims struct {
|
|
|
+ UserName string `json:"userName"`
|
|
|
+ TokenType int `json:"tokenType"` //0 token 登录 1:刷新token
|
|
|
+ jwt.RegisteredClaims
|
|
|
+}
|
|
|
+
|
|
|
+// 生成jwt token
|
|
|
+func GetJwtToken(UserName string, tokenType int) (string, error) {
|
|
|
+ mySigningKey := []byte(config.Get("app.JwtSecret"))
|
|
|
+ timeData := time.Second
|
|
|
+ if tokenType == 0 {
|
|
|
+ timeData = time.Duration(config.GetInt("app.api_exp")) * time.Second
|
|
|
+ } else {
|
|
|
+ timeData = 24 * time.Hour
|
|
|
+ }
|
|
|
+ claims := MyCustomClaims{
|
|
|
+ UserName,
|
|
|
+ tokenType,
|
|
|
+ jwt.RegisteredClaims{
|
|
|
+ // A usual scenario is to set the expiration time relative to the current time
|
|
|
+ ExpiresAt: jwt.NewNumericDate(time.Now().Add(timeData)),
|
|
|
+ IssuedAt: jwt.NewNumericDate(time.Now()),
|
|
|
+ NotBefore: jwt.NewNumericDate(time.Now()),
|
|
|
+ Issuer: "test",
|
|
|
+ Subject: "somebody",
|
|
|
+ ID: "1",
|
|
|
+ Audience: []string{"somebody_else"},
|
|
|
+ },
|
|
|
+ }
|
|
|
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
|
+ ss, err := token.SignedString(mySigningKey)
|
|
|
+ return ss, err
|
|
|
+}
|
|
|
+
|
|
|
+/* 解析jwt */
|
|
|
+func ParseJwtWithClaims(tokenString string) (string, int) {
|
|
|
+ token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
|
|
|
+ return []byte(config.Get("app.JwtSecret")), nil
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ // fmt.Println(err)
|
|
|
+ return "", 0
|
|
|
+ } else if claims, ok := token.Claims.(*MyCustomClaims); ok {
|
|
|
+ // fmt.Println(claims.OpenId, claims.RegisteredClaims.Issuer)
|
|
|
+ return claims.UserName, claims.TokenType
|
|
|
+ } else {
|
|
|
+ // fmt.Println("unknown claims type, cannot proceed")
|
|
|
+ return "", 0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 刷新Token
|
|
|
+func RefreshToken(oldToken string) (string, error) {
|
|
|
+ token, err := jwt.Parse(oldToken, func(*jwt.Token) (interface{}, error) {
|
|
|
+ return config.Get("app.JwtSecret"), nil
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
|
|
+ claims["exp"] = time.Now().Add(time.Duration(config.GetInt("app.api_exp")) * time.Second).Unix() // 更新过期时间
|
|
|
+ return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(config.Get("app.JwtSecret"))
|
|
|
+ }
|
|
|
+ return "", err
|
|
|
+}
|
|
|
+
|
|
|
+// 返回剩余时间
|
|
|
+func GetRemainderTime(timeType int) (time.Duration, error) {
|
|
|
+ var remaining time.Duration
|
|
|
+ err := errors.New("发生错误")
|
|
|
+ //获取当前时间
|
|
|
+ now := time.Now()
|
|
|
+ switch timeType {
|
|
|
+ case 2:
|
|
|
+ //计算本日剩余时间
|
|
|
+ endOfDay := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())
|
|
|
+ remaining = endOfDay.Sub(now)
|
|
|
+ case 3:
|
|
|
+ //计算本周剩余时间
|
|
|
+ daysUntiEndOfWeek := 6 - now.Weekday()
|
|
|
+ endOfWeek := time.Date(now.Year(), now.Month(), now.Day()+int(daysUntiEndOfWeek), 23, 59, 59, 0, now.Location())
|
|
|
+ remaining = endOfWeek.Sub(now)
|
|
|
+ case 4:
|
|
|
+ //计算本月剩余时间
|
|
|
+ // endOfMonth := time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, now.Location()).Add(-time.Second)
|
|
|
+ // remaining = endOfMonth.Sub(now)
|
|
|
+ nextMonth := now.AddDate(0, 1, 0)
|
|
|
+ endOfMonth := time.Date(nextMonth.Year(), nextMonth.Month(), 1, 0, 0, 0, 0, nextMonth.Location()).Add(-time.Second)
|
|
|
+ remaining = endOfMonth.Sub(now)
|
|
|
+ default:
|
|
|
+ return remaining, err
|
|
|
+ }
|
|
|
+
|
|
|
+ // fmt.Printf("Remaning day data:%v\n", remaining)
|
|
|
+ // fmt.Printf("Remaning week data:%v\n", remaining)
|
|
|
+ // fmt.Printf("Remaning month data:%v\n", remaining)
|
|
|
+ return remaining, nil
|
|
|
+}
|