mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 17:50:12 +00:00
feat(jwt): server-side session table with keyId + obfuscated uid claims
Replace the {user_id, ip} claim pair with {keyId, uid}:
- keyId is a 32-byte random id that points to a row in the new
jwt_sessions table holding the real user id, bound IP, UA hash,
TokenVersion and expiry.
- uid is the user id encoded through pkg/idcodec; mismatch between
claim uid and session.UserID trips WAF block on the caller IP.
- identityHandler now rejects unknown/revoked/expired sessions, IP
drift and stale TokenVersion. Refresh updates session.ExpiresAt.
User.TokenVersion bumps on password change and revokes outstanding
sessions, so a leaked JWT secret alone is no longer enough to forge
a token. JWTSession rows are GC'd every 10 minutes (expired + grace
or revoked >24h). OAuth2 callback shares the same issue path.
Includes regression tests for happy path, mismatched claim uid,
revoked session, TokenVersion bump, IP drift and unknown keyId.
Co-authored-by: cloudcode <cloudcode@users.noreply.github.com>
This commit is contained in:
@@ -187,10 +187,15 @@ func oauth2callback(jwtConfig *jwt.GinJWTMiddleware) func(c *gin.Context) (any,
|
||||
}
|
||||
}
|
||||
|
||||
tokenString, _, err := jwtConfig.TokenGenerator(map[string]interface{}{
|
||||
"user_id": fmt.Sprintf("%d", bind.UserID),
|
||||
"ip": realip,
|
||||
})
|
||||
var bindUser model.User
|
||||
if err := singleton.DB.First(&bindUser, bind.UserID).Error; err != nil {
|
||||
return nil, newGormError("%v", err)
|
||||
}
|
||||
claims, err := issueJWTSession(c, &bindUser, singleton.Conf.JWTTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenString, _, err := jwtConfig.TokenGenerator(claims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user