{"record":{"id":"36c4b5672eb9e7d7","repo":"dromara/Sa-Token","slug":"nonce","errorCode":null,"errorMessage":"nonce 为空，无效","messagePattern":"nonce 为空，无效","errorType":"exception","errorClass":"SaSignException","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-sign/src/main/java/cn/dev33/satoken/sign/template/SaSignTemplate.java","lineNumber":270,"sourceCode":"\t\t// 为空代表无效\n\t\tif(SaFoxUtil.isEmpty(nonce)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// 校验此 nonce 是否已被使用过\n\t\tString key = splicingNonceSaveKey(nonce);\n\t\treturn SaManager.getSaTokenDao().get(key) == null;\n\t}\n\n\t/**\n\t * 校验：随机字符串 nonce 是否有效，如果无效则抛出异常。\n\t * \t\t注意：同一 nonce 只可以被校验通过一次，校验后将保存在缓存中，再次校验将无法通过\n\t * @param nonce 待校验的随机字符串\n\t */\n\tpublic void checkNonce(String nonce) {\n\t\t// 为空代表无效\n\t\tif(SaFoxUtil.isEmpty(nonce)) {\n\t\t\tthrow new SaSignException(\"nonce 为空，无效\");\n\t\t}\n\n\t\t// 校验此 nonce 是否已被使用过\n\t\tString key = splicingNonceSaveKey(nonce);\n\t\tif(SaManager.getSaTokenDao().get(key) != null) {\n\t\t\tthrow new SaSignException(\"此 nonce 已被使用过，不可重复使用：\" + nonce);\n\t\t}\n\n\t\t// 校验通过后，将此 nonce 保存在缓存中，保证下次校验无法通过\n\t\tSaManager.getSaTokenDao().set(key, nonce, getSignConfigOrGlobal().getSaveNonceExpire() * 2 + 2);\n\t}\n\n\t/**\n\t * 判断：给定的参数 生成的签名是否为有效签名\n\t * @param paramsMap 参数列表\n\t * @param sign 待验证的签名\n\t * @return 签名是否有效\n\t */","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-sign/src/main/java/cn/dev33/satoken/sign/template/SaSignTemplate.java#L252-L288","documentation":"Thrown by SaSignTemplate.checkNonce when the nonce parameter is empty/blank (SaSignException with no specific code). The anti-replay mechanism requires every signed request to carry a unique random nonce; an absent one cannot be recorded or checked, so the request is rejected immediately.","triggerScenarios":"Sending a signed API request where the nonce parameter is missing, empty string, or whitespace, e.g. after client code forgot to put it into the parameter map before signing.","commonSituations":"New client integration omits nonce from the signed parameter set; a filter strips unknown parameters; parameter name mismatch (nm vs nonce) between client convention and server config; copy-paste test code without the nonce entry.","solutions":["Include a fresh random nonce in every signed request: params.put(\"nonce\", SaFoxUtil.getRandomString(32))","Ensure the nonce parameter name matches the configured one and is included in the signature computation and the HTTP payload","Regenerate nonce per request — never hardcode or reuse it"],"exampleFix":"// before\nMap<String,String> p = buildBizParams(); String sign = createSign(p);\n// after\np.put(\"nonce\", SaFoxUtil.getRandomString(32));\np.put(\"timestamp\", String.valueOf(System.currentTimeMillis()));\nString sign = createSign(p);","handlingStrategy":"validation","validationCode":"if (SaFoxUtil.isEmpty(nonce)) throw new IllegalArgumentException(\"nonce is required for signed requests\");","typeGuard":null,"tryCatchPattern":"try { saSignTemplate.checkNonce(nonce); } catch (SaSignException e) { return status(401, \"missing or invalid nonce\"); }","preventionTips":["Generate nonce in the same helper that builds and signs the request so it can never be forgotten","Include nonce in the signed parameter map, not appended afterward"],"tags":["api-sign","nonce","replay-protection","validation"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}