middleHandle.go 6.16 KB
Newer Older
chenweijian's avatar
chenweijian committed
1 2 3 4
package route

import (
	"bytes"
chenweijian's avatar
chenweijian committed
5 6
	"crypto/md5"
	"fmt"
hujiebin's avatar
hujiebin committed
7 8 9
	"git.hilo.cn/hilo-common/mycontext"
	"git.hilo.cn/hilo-common/mylogrus"
	"git.hilo.cn/hilo-common/resource/config"
hujiebin's avatar
hujiebin committed
10
	"git.hilo.cn/hilo-common/utils"
chenweijian's avatar
chenweijian committed
11 12 13 14 15 16 17
	"github.com/gin-gonic/gin"
	"hilo-user/myerr/bizerr"
	"hilo-user/req"
	"hilo-user/req/jwt"
	"hilo-user/resp"
	"io/ioutil"
	"runtime/debug"
chenweijian's avatar
chenweijian committed
18
	"strconv"
chenweijian's avatar
chenweijian committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
	"strings"
	"time"
)

/**
controller层全局异常处理
*/

// 等级最高,为了只为最后有返回值到前端
func ExceptionHandle(c *gin.Context) {
	defer func() {
		if r := recover(); r != nil {
			//打印错误堆栈信息
			mylogrus.MyLog.Errorf("ExceptionHandle SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
			resp.ResponseErrWithString(c, r)
			//终止后续接口调用,不加的话recover到异常后,还会继续执行接口里后续代码
			c.Abort()
		}
	}()
	c.Next()
}

// jwt解密
func JWTApiHandle(c *gin.Context) {
	logger := mylogrus.MyLog.WithField("URL", c.Request.URL).WithField("METHOD", c.Request.Method)
	token := c.GetHeader("token")
	if token == "" {
		logger.Warnf("token err is empty! %v", c.Request.Header)
		resp.ResponseBusiness(c, bizerr.TokenInvalid)
		c.Abort()
		return
	}
	claims, err := jwt.ParseToken(token)
	if err != nil {
		logger.Warnf("token parsed err:%v", err)
		resp.ResponseBusiness(c, bizerr.TokenInvalid)
		c.Abort()
		return
	}
	logger = logger.WithField("userId", claims.UserId)
	if time.Now().Unix() > claims.ExpiresAt {
		logger.Warnf("token expire err, now: %d, expiresAt %d", time.Now().Unix(), claims.ExpiresAt)
		resp.ResponseBusiness(c, bizerr.TokenInvalid)
		c.Abort()
		return
	}
	if claims.Issuer != config.GetConfigJWT().ISSUER_API {
		logger.Warnf("token err issuer:%s, configIssuer %s", claims.Issuer, config.GetConfigJWT().ISSUER_API)
		resp.ResponseBusiness(c, bizerr.TokenInvalid)
		c.Abort()
		return
	}
	var newToken = token
	// token 连续7天没玩,第八天回来后给新token(线上是30天过期)
	if claims.ExpiresAt-time.Now().Unix() < 86400*7 {
		logger.Infof("token nearly expire err, now:%d,expiresAt:%d", time.Now().Unix(), claims.ExpiresAt)
		newToken, err = jwt.GenerateToken(claims.UserId, claims.ExternalId, config.GetConfigJWT().ISSUER_API)
		if err != nil {
			logger.Warnf("token generation failed, err:%v", err)
			resp.ResponseBusiness(c, bizerr.TokenInvalid)
			c.Abort()
			return
		}
	}

hujiebin's avatar
hujiebin committed
84 85
	c.Set(mycontext.USERID, claims.UserId)
	c.Set(mycontext.EXTERNAL_ID, claims.ExternalId)
chenweijian's avatar
chenweijian committed
86 87 88 89 90 91 92 93 94 95 96

	c.Writer.Header().Add("token", newToken)
	c.Next()
}

// 日志Handle
func LoggerHandle(c *gin.Context) {
	//开始时间
	start := time.Now()
	clientIp := c.ClientIP()
	method := c.Request.Method
hujiebin's avatar
hujiebin committed
97
	traceId := genTraceId(c)
chenweijian's avatar
chenweijian committed
98
	reqUri := c.Request.RequestURI
hujiebin's avatar
hujiebin committed
99
	c.Set(mycontext.TRACEID, traceId)
chenweijian's avatar
chenweijian committed
100 101 102 103
	//
	header := c.Request.Header
	//类型
	devicetype := header.Get("Devicetype")
hujiebin's avatar
hujiebin committed
104
	c.Set(mycontext.DEVICETYPE, devicetype)
chenweijian's avatar
chenweijian committed
105
	appVersion := header.Get("Appversion")
hujiebin's avatar
hujiebin committed
106 107 108
	c.Set(mycontext.APP_VERSION, appVersion)
	c.Set(mycontext.URL, reqUri)
	c.Set(mycontext.METHOD, method)
hujiebin's avatar
hujiebin committed
109 110 111 112 113 114
	lang := header.Get(mycontext.LANGUAGE)
	c.Set(mycontext.LANGUAGE, lang)
	carrier := header.Get(mycontext.CARRIER)
	c.Set(mycontext.CARRIER, carrier)
	timezone := header.Get(mycontext.TIMEZONE)
	c.Set(mycontext.TIMEZONE, timezone)
chenweijian's avatar
chenweijian committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

	userId, _ := req.GetUserId(c)

	bodyStr := ""
	contentType := c.Request.Header.Get("Content-Type")

	//文件就不打印
	if strings.Index(contentType, "multipart/form-data") == -1 {
		data, err := c.GetRawData()
		if err != nil {
			mylogrus.MyLog.Errorf("handle log err:%v", err)
		}
		bodyStr = string(data)
		//很关键
		//把读过的字节流重新放到body
		c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
	}

	mycontext.CreateMyContext(c.Keys).Log.Infof("request start traceId:%v, clientIp:%v, url:%v, method:%v, userId:%v, body:%v, header:%v", traceId, clientIp, reqUri, method, userId, bodyStr, header)
	//加载完 defer recover,继续后续接口调用
	c.Next()
	end := time.Now()
	latency := end.Sub(start)
	mycontext.CreateMyContext(c.Keys).Log.Infof("request end fullPath:%v,url:%v, method: %v, traceId:%v, latency:%v userId:%v", c.FullPath(), reqUri, method, traceId, latency, userId)
}
hujiebin's avatar
hujiebin committed
140 141 142 143 144 145 146 147 148 149 150 151

// 加密Handle
func EncryptHandle(c *gin.Context) {
	header := c.Request.Header
	appVersion := header.Get("Appversion")
	if len(appVersion) > 0 {
		if high, _ := utils.CompareVersion(appVersion, "> 3.9.0"); high {
			c.Set(mycontext.InnerEncrypt, true)
		}
	}
	c.Next()
}
chenweijian's avatar
chenweijian committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

//http信息解密(web)
func HttpWebSecretHandle(c *gin.Context) {
	traceId, _ := c.Keys[mycontext.TRACEID]

	timestamp := c.GetHeader("timestamp") //时间戳,单位秒
	nonce := c.GetHeader("nonce")         //随机数字
	signature := c.GetHeader("signature") //sha1加密结果
	mylogrus.MyLog.Debugf("handle secret begin timestamp:%v, nonce:%v, signature:%v traceId:%v", timestamp, nonce, signature, traceId)

	if nonce == "hilo" {
		mylogrus.MyLog.Infof("no check http secret handle")
	} else {
		if timestamp == "" || nonce == "" || signature == "" {
			resp.ResponseBusiness(c, bizerr.HttpSecret)
			c.Abort()
			return
		}
		timestampInt, err := strconv.ParseInt(timestamp, 10, 64)
		if err != nil {
			resp.ResponseBusiness(c, bizerr.HttpSecret)
			c.Abort()
			return
		}
		nowTimestamp := time.Now().Unix()
		v := nowTimestamp - timestampInt
		//10分钟内有效,改成60分钟,20210402产品让我改成60分钟,原因:依旧有用户时间戳不对,达到了30分钟
		if v < -60*60 || v > 60*60 {
			mylogrus.MyLog.Warnf("handle secret err, timestampInt:%v, nowTimestamp:%v, v:%v, traceId:%v", timestampInt, nowTimestamp, v, traceId)
			//2021/11/05 产品让我关的,因为中东用户时间戳有问题
			/*			ResponseBusiness(c, bizerr.HttpSecret)
						c.Abort()
						return*/
		}
		str := timestamp + config.GetConfigApp().WEB_SECRET + nonce
		//避免web的暴露,让用户知道app的api加密方式。
		h := md5.New()
		//h := sha1.New()
		h.Write([]byte(str))
		newSignature := fmt.Sprintf("%x", h.Sum(nil))

		//newSignature := string(sha1.New().Sum([]byte(str))[:])
		if signature != newSignature {
			mylogrus.MyLog.Errorf("handle secret err signature:%v, newSignature:%v, traceId:%v", signature, newSignature, traceId)
			resp.ResponseBusiness(c, bizerr.HttpSecret)
			c.Abort()
			return
		}
	}
	c.Next()
}