From ca3d847bbb0067a89adfc627a6c4680b3dcdca07 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Thu, 16 Apr 2026 19:41:18 +0530 Subject: [PATCH 1/3] jwt authentication enabled --- config/config.go | 5 +++ middleware/middleware.go | 66 ++++++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/config/config.go b/config/config.go index 8432fa6..2e38951 100644 --- a/config/config.go +++ b/config/config.go @@ -21,6 +21,7 @@ type appConfig struct { TokenExpireTime int64 Environment string `json:"environment" validate:"required"` TenantName string `json:"tenant_name" validate:"required"` + JWTSecret string } type dbConfig struct { Write dbConfigObj @@ -206,6 +207,10 @@ func LoadConfig() *appConfig { if k == "environment" { config.Environment = v.(string) } + + if k == "jwt_secret" { + config.JWTSecret = v.(string) + } } } config.DBUser.Write = dbObj diff --git a/middleware/middleware.go b/middleware/middleware.go index c04e315..8ef4477 100644 --- a/middleware/middleware.go +++ b/middleware/middleware.go @@ -6,13 +6,17 @@ import ( "net/http" "reflect" + "com.lc.go.codepush/server/config" "com.lc.go.codepush/server/model" "com.lc.go.codepush/server/model/constants" "com.lc.go.codepush/server/utils" "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v4" ) -// 檢查token +// CheckToken authenticates via the "token" cookie or header. +// It first attempts to parse the value as a JWT (from app-center-server). +// If JWT validation fails, it falls back to the existing DB token lookup. func CheckToken(ctx *gin.Context) { var token, _ = ctx.Cookie("token") if token == "" { @@ -23,27 +27,63 @@ func CheckToken(ctx *gin.Context) { log.Panic("Token can't null") } + // 1. Try JWT validation + if uid, ok := validateJWT(token); ok { + ctx.Set(constants.GIN_USER_ID, uid) + return + } + + // 2. Fall back to existing DB token lookup (UUID from code-push login) tokenNow := model.GetOne[model.Token]("token=?", token) + if tokenNow == nil || tokenNow.ExpireTime == nil || tokenNow.Del == nil { + ctx.JSON(http.StatusUnauthorized, gin.H{"code": 1100, "msg": "Invalid token"}) + ctx.Abort() + return + } if *utils.GetTimeNow() > *tokenNow.ExpireTime || *tokenNow.Del { - ctx.JSON(http.StatusInternalServerError, gin.H{ - "code": 1100, - "msg": "Token expire", - }) + ctx.JSON(http.StatusUnauthorized, gin.H{"code": 1100, "msg": "Token expired"}) ctx.Abort() - } else { - if (tokenNow != nil && tokenNow.Del != nil && *tokenNow.Del) || tokenNow == nil { - ctx.JSON(http.StatusInternalServerError, gin.H{ - "code": 1100, - "msg": "Token expire", - }) - ctx.Abort() - } + return } ctx.Set(constants.GIN_USER_ID, *tokenNow.Uid) } +// validateJWT tries to parse tokenStr as an HS256 JWT signed with JWT_SECRET. +// Returns (uid, true) on success. Returns (0, false) silently on any failure +// so the caller can fall back to DB token lookup. +// validateJWT validates the token against the shared JWT_SECRET. +// If the signature and claims are valid, authentication passes — no DB lookup needed. +// Returns (default admin uid, true) on success so downstream handlers have a valid uid. +func validateJWT(tokenStr string) (int, bool) { + secret := config.GetConfig().JWTSecret + if secret == "" { + return 0, false + } + + token, err := jwt.Parse(tokenStr, func(t *jwt.Token) (interface{}, error) { + if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, jwt.ErrSignatureInvalid + } + return []byte(secret), nil + }) + if err != nil || !token.Valid { + return 0, false + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return 0, false + } + + if email, _ := claims["email"].(string); email == "" { + return 0, false + } + + return 1, true +} + // 異常處理 func Recover(c *gin.Context) { c.Writer.Header().Add("Access-Control-Allow-Origin", "*") From 0581b9b80be168a016e3e7a40245d2244e3e26ac Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Thu, 16 Apr 2026 19:43:22 +0530 Subject: [PATCH 2/3] jwt authentication enabled --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index caa96d3..2ba51b7 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect diff --git a/go.sum b/go.sum index aeee0a5..01a8140 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,8 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= From 1cbacf2aed04c7d2c60efc177194de46a0ed93c6 Mon Sep 17 00:00:00 2001 From: Kshitij Singh Date: Sun, 26 Apr 2026 23:10:33 +0530 Subject: [PATCH 3/3] jwt middleware changes --- config/config.go | 2 +- go.mod | 2 +- middleware/middleware.go | 16 +++++++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/config/config.go b/config/config.go index 2e38951..93b2948 100644 --- a/config/config.go +++ b/config/config.go @@ -21,7 +21,7 @@ type appConfig struct { TokenExpireTime int64 Environment string `json:"environment" validate:"required"` TenantName string `json:"tenant_name" validate:"required"` - JWTSecret string + JWTSecret string `json:"jwt_secret" validate:"required"` } type dbConfig struct { Write dbConfigObj diff --git a/go.mod b/go.mod index 2ba51b7..27ed4cb 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect diff --git a/middleware/middleware.go b/middleware/middleware.go index 8ef4477..c400adf 100644 --- a/middleware/middleware.go +++ b/middleware/middleware.go @@ -5,6 +5,7 @@ import ( "log" "net/http" "reflect" + "strings" "com.lc.go.codepush/server/config" "com.lc.go.codepush/server/model" @@ -24,7 +25,12 @@ func CheckToken(ctx *gin.Context) { } if token == "" { - log.Panic("Token can't null") + ctx.JSON(http.StatusUnauthorized, gin.H{ + "code": 1100, + "msg": "Token required", + }) + ctx.Abort() + return } // 1. Try JWT validation @@ -35,7 +41,7 @@ func CheckToken(ctx *gin.Context) { // 2. Fall back to existing DB token lookup (UUID from code-push login) tokenNow := model.GetOne[model.Token]("token=?", token) - if tokenNow == nil || tokenNow.ExpireTime == nil || tokenNow.Del == nil { + if tokenNow == nil || tokenNow.ExpireTime == nil || tokenNow.Del == nil || tokenNow.Uid == nil { ctx.JSON(http.StatusUnauthorized, gin.H{"code": 1100, "msg": "Invalid token"}) ctx.Abort() return @@ -77,11 +83,15 @@ func validateJWT(tokenStr string) (int, bool) { return 0, false } + email := "" if email, _ := claims["email"].(string); email == "" { return 0, false } + if strings.HasSuffix(email, "@punchh.com") || strings.HasSuffix(email, "@partech.com") { + return 1, true + } - return 1, true + return 0, false } // 異常處理