{"record":{"id":"02da42ccf6737126","repo":"flipped-aurora/gin-vue-admin","slug":"error-02da42","errorCode":null,"errorMessage":"无效签名","messagePattern":"无效签名","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/utils/jwt.go","lineNumber":22,"sourceCode":"\t\"context\"\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/flipped-aurora/gin-vue-admin/server/global\"\n\t\"github.com/flipped-aurora/gin-vue-admin/server/model/system/request\"\n\tjwt \"github.com/golang-jwt/jwt/v5\"\n)\n\ntype JWT struct {\n\tSigningKey []byte\n}\n\nvar (\n\tTokenValid            = errors.New(\"未知错误\")\n\tTokenExpired          = errors.New(\"token已过期\")\n\tTokenNotValidYet      = errors.New(\"token尚未激活\")\n\tTokenMalformed        = errors.New(\"这不是一个token\")\n\tTokenSignatureInvalid = errors.New(\"无效签名\")\n\tTokenInvalid          = errors.New(\"无法处理此token\")\n)\n\nfunc NewJWT() *JWT {\n\treturn &JWT{\n\t\t[]byte(global.GVA_CONFIG.JWT.SigningKey),\n\t}\n}\n\nfunc (j *JWT) CreateClaims(baseClaims request.BaseClaims) request.CustomClaims {\n\tbf, _ := ParseDuration(global.GVA_CONFIG.JWT.BufferTime)\n\tep, _ := ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)\n\tclaims := request.CustomClaims{\n\t\tBaseClaims: baseClaims,\n\t\tBufferTime: int64(bf / time.Second), // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失\n\t\tRegisteredClaims: jwt.RegisteredClaims{\n\t\t\tAudience:  jwt.ClaimStrings{\"GVA\"},                   // 受众\n\t\t\tNotBefore: jwt.NewNumericDate(time.Now().Add(-1000)), // 签名生效时间","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/utils/jwt.go#L4-L40","documentation":"TokenSignatureInvalid is returned by ParseToken when the JWT's signature fails verification: the token was signed with a key different from JWT.SigningKey, or its payload/signature segments were altered after issuance.","triggerScenarios":"Tokens issued by an environment whose JWT.SigningKey differs from the validating server's config; manually edited tokens; key rotation on the server invalidating previously issued tokens.","commonSituations":"Multi-node deployments with inconsistent config.yaml signing keys; dev/prod keys mixed up (token from dev used against prod); a config change rotating the key while clients still hold old tokens.","solutions":["Ensure every server instance uses the same JWT.SigningKey value in config.yaml (or shared secret manager).","Re-login/re-issue the token after any signing-key rotation.","If this is a dev/prod mix-up, use the token issued for the environment you are calling.","Diff the signing key against the issuer's to confirm which mismatch exists before rotating."],"exampleFix":"// before\n# node A config.yaml\njwt:\n  signing-key: 'abc'\n# node B config.yaml\njwt:\n  signing-key: 'xyz'   # tokens from A fail on B: 无效签名\n// after\njwt:\n  signing-key: 'abc'   # identical on all nodes","handlingStrategy":"validation","validationCode":"// ops check before deploy\n// grep -r 'signing-key' server/config.yaml  -> must match issuer's key\nif cfg.JWT.SigningKey == \"\" || cfg.JWT.SigningKey != expectedKey {\n    return errors.New(\"signing key mismatch across nodes\")\n}","typeGuard":null,"tryCatchPattern":"claims, err := utils.ParseToken(token)\nif errors.Is(err, utils.TokenSignatureInvalid) {\n    // token from another environment or tampered: reject, force re-login\n    return nil, ErrSignatureMismatch\n}","preventionTips":["Distribute JWT.SigningKey via a shared secret store so all replicas match","Rotate keys deliberately: bump a key-version, re-issue tokens, keep old key for a grace window","Never hand-edit token payload segments; signature verification will reject them"],"tags":["jwt","auth","go","signature-verification"],"backgroundTag":"jwt-signature-invalid","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}