package middleware import ( "encoding/json" "nCovTrack-Backend/global" "nCovTrack-Backend/models" "nCovTrack-Backend/utils" "net/http" "strconv" "time" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" ) const UNAUTH_MSG = "unauthorized" func Auth() gin.HandlerFunc { return func(c *gin.Context) { oldToken := c.Request.Header["Token"] c.Writer.Header().Set("X-Token", "") if len(oldToken) != 1 || oldToken[0] == "" { utils.Err(c, http.StatusUnauthorized, http.StatusUnauthorized, UNAUTH_MSG) c.Abort() return } // Write the field of token to request header claims := utils.ParseClaims(oldToken[0]) tokenClaims := models.TokenClaims{ ID: int(claims["id"].(float64)), Username: claims["username"].(string), Email: claims["email"].(string), Role: int(claims["role"].(float64)), Region: claims["region"].(string), } claimsByte, _ := json.Marshal(tokenClaims) c.Request.Header.Add("claims", string(claimsByte)) // renew token, and judge the token's iat is expired or not renewToken := utils.RenewToken(oldToken[0]) if renewToken == "" || !validAccountIssue(claims) { utils.Err(c, http.StatusUnauthorized, http.StatusUnauthorized, UNAUTH_MSG) c.Abort() return } c.Writer.Header().Set("X-Token", renewToken) c.Next() } } // validAccountIssue validate token is valid or not // If user change password, or logoff on all password, we need to judge use's token is valid? // Due to the token is no status, so we need to record something on the server-end. // We use the "IssueAt" field of token, to judge token expired or not. // TODO: Move this to jwt utils func validAccountIssue(claims jwt.MapClaims) bool { iafStr := global.Redis.HGet(global.CHANGEPWD_REDIS_KEY, claims["email"].(string)).Val() if iafStr == "" { return true } iaf, _ := strconv.Atoi(iafStr) // Due to we allow token renew, although it was expired, so the token validity period will more than token's validity period tokenMaxValidSeconds := (global.TOKEN_EXPIRE_DAYS + global.ServerSettings.Jwt.RenewExpireDays) * 24 * 60 * 60 if time.Now().Unix()-int64(iaf) > int64(tokenMaxValidSeconds) { global.Redis.HDel(global.CHANGEPWD_REDIS_KEY, claims["email"].(string)) return true } return int(claims["iat"].(float64)) > iaf }