middleHandle.go 5.86 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"
chenweijian's avatar
chenweijian committed
10 11 12 13 14 15 16
	"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
17
	"strconv"
chenweijian's avatar
chenweijian committed
18 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
	"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
83 84
	c.Set(mycontext.USERID, claims.UserId)
	c.Set(mycontext.EXTERNAL_ID, claims.ExternalId)
chenweijian's avatar
chenweijian committed
85 86 87 88 89 90 91 92 93 94 95

	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
96
	traceId := genTraceId(c)
chenweijian's avatar
chenweijian committed
97
	reqUri := c.Request.RequestURI
hujiebin's avatar
hujiebin committed
98
	c.Set(mycontext.TRACEID, traceId)
chenweijian's avatar
chenweijian committed
99 100 101 102
	//
	header := c.Request.Header
	//类型
	devicetype := header.Get("Devicetype")
hujiebin's avatar
hujiebin committed
103
	c.Set(mycontext.DEVICETYPE, devicetype)
chenweijian's avatar
chenweijian committed
104
	appVersion := header.Get("Appversion")
hujiebin's avatar
hujiebin committed
105 106 107
	c.Set(mycontext.APP_VERSION, appVersion)
	c.Set(mycontext.URL, reqUri)
	c.Set(mycontext.METHOD, method)
hujiebin's avatar
hujiebin committed
108 109 110 111 112 113
	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
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138

	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)
}
chenweijian's avatar
chenweijian committed
139 140 141 142 143 144 145 146 147 148 149 150 151 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

//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()
}