{"record":{"id":"17520c8a6dfbdd01","repo":"dromara/Sa-Token","slug":"30203","errorCode":"30203","errorMessage":"jwt loginType 无效：","messagePattern":"jwt loginType 无效：","errorType":"exception","errorClass":"SaJwtException","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtTemplate.java","lineNumber":198,"sourceCode":"    \t\n    \t// 解析 \n    \tJWT jwt;\n    \ttry {\n    \t\tjwt = JWT.of(token);\n\t\t} catch (JWTException | JSONException e) {\n    \t\tthrow new SaJwtException(\"jwt 解析失败：\" + token, e).setCode(SaJwtErrorCode.CODE_30201);\n\t\t}\n    \tJSONObject payloads = jwt.getPayloads();\n    \t\n    \t// 校验 Token 签名\n\t\tboolean verify = jwt.setSigner(createSigner(keyt)).verify();\n    \tif( ! verify) {\n    \t\tthrow new SaJwtException(\"jwt 签名无效：\" + token).setCode(SaJwtErrorCode.CODE_30202);\n    \t}\n\n    \t// 校验 loginType \n    \tif( ! Objects.equals(loginType, payloads.getStr(LOGIN_TYPE))) {\n    \t\tthrow new SaJwtException(\"jwt loginType 无效：\" + token).setCode(SaJwtErrorCode.CODE_30203);\n    \t}\n    \t\n    \t// 校验 Token 有效期\n    \tif(isCheckTimeout) {\n    \t\tLong effTime = payloads.getLong(EFF, 0L);\n        \tif(effTime != NEVER_EXPIRE) {\n        \t\tif(effTime == null || effTime < System.currentTimeMillis()) {\n        \t\t\tthrow new SaJwtException(\"jwt 已过期：\" + token).setCode(SaJwtErrorCode.CODE_30204);\n        \t\t}\n        \t}\n    \t}\n    \t\n        // 返回 \n        return jwt;\n    }\n\n    /**\n     * 获取 jwt 数据载荷 （校验 sign、loginType、timeout） ","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtTemplate.java#L180-L216","documentation":"Thrown by SaJwtTemplate.parseToken when the token's payload loginType claim does not equal the loginType argument passed to parseToken. Sa-token embeds the account system (loginType, e.g. 'login' or a custom StpLogic type) in each JWT; code 30203 marks a mismatch.","triggerScenarios":"Parsing a token issued for StpLogic 'login' while passing loginType 'user' (or vice versa) — e.g. a multi-account-type app where the wrong StpLogic or hard-coded loginType is used during verification.","commonSituations":"Custom StpLogic with a new loginType but the token was created under the default type; copying verification code from another account-type module and forgetting to change the loginType string; frontend sending a token from app A to app B which share a secret but not a loginType.","solutions":["Make the loginType used in parseToken match the StpLogic that issued the token (use stpLogic.getLoginType(), not a literal)","If tokens are shared across services, standardize one loginType for issuance and verification","Inspect the token's payload (decode the middle segment) to see which loginType claim it carries"],"exampleFix":"// before\n// token was issued by StpUtil (loginType=\"login\")\nstpLogicUser.getStpLogicJwt().parseToken(token, \"user\", secret, true); // 30203\n\n// after\n// verify with the loginType that issued the token\nstpLogicUser.getStpLogicJwt().parseToken(token, \"login\", secret, true);\n// or generically: parseToken(token, issuingStpLogic.getLoginType(), secret, true);","handlingStrategy":"validation","validationCode":"// verify with the issuing logic's own loginType\nString loginType = issuingStpLogic.getLoginType();\npayloads = jwtTemplate.parseToken(token, loginType, secret, false).getPayloads();\nif (!Objects.equals(expectedType, payloads.getStr(\"loginType\"))) { ... }","typeGuard":null,"tryCatchPattern":"catch (SaJwtException e) { if (e.getCode() == SaJwtErrorCode.CODE_30203) { /* token from wrong account system: 401 */ } }","preventionTips":["Derive loginType from the StpLogic constant instead of string literals","In multi-app SSO, namespace tokens by app and verify the namespace claim explicitly"],"tags":["sa-token","jwt","login-type","multi-account"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}