{"record":{"id":"0bef2113ebf347b8","repo":"jeecgboot/JeecgBoot","slug":"appkey-0bef21","errorCode":null,"errorMessage":"appkey错误","messagePattern":"appkey错误","errorType":"exception","errorClass":"JeecgBootException","httpStatus":null,"severity":"error","filePath":"jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/filter/ApiAuthFilter.java","lineNumber":227,"sourceCode":"        }\n    }\n\n    /**\n     * 认证信息核验\n     * @param appKey\n     * @param signature\n     * @param timestamp\n     * @param openApiAuth\n     * @return\n     * @throws Exception\n     */\n    protected void checkSignature(String appKey, String signature, String timestamp, OpenApiAuth openApiAuth) {\n        if(openApiAuth==null){\n            throw new JeecgBootException(\"不存在认证信息\");\n        }\n\n        if(!appKey.equals(openApiAuth.getAk())){\n            throw new JeecgBootException(\"appkey错误\");\n        }\n\n        if (!signature.equals(md5(appKey + openApiAuth.getSk() + timestamp))) {\n            throw new JeecgBootException(\"signature签名错误\");\n        }\n    }\n\n    protected void checkPermission(OpenApi openApi, OpenApiAuth openApiAuth) {\n        List<OpenApiPermission> permissionList = openApiPermissionService.findByAuthId(openApiAuth.getId());\n\n        boolean hasPermission = false;\n        for (OpenApiPermission permission : permissionList) {\n            if (permission.getApiId().equals(openApi.getId())) {\n                hasPermission = true;\n                break;\n            }\n        }\n","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/filter/ApiAuthFilter.java#L209-L245","documentation":"Thrown by checkSignature when the supplied appKey does not equal openApiAuth.getAk(). This is a defensive equality check: the lookup already found a row by appkey, but the code re-asserts equality, catching mismatches caused by case differences, trailing whitespace, or lookup logic that matched on a partial/normalized key.","triggerScenarios":"Caller sends appkey with different case or surrounding whitespace than stored; the auth service's lookup matched on a normalized form; concurrent update changed the stored ak between lookup and check.","commonSituations":"Client trims/uppercases the appkey before sending; copy-paste introduced whitespace; database collation matched case-insensitively but the .equals() is case-sensitive.","solutions":["Send the appkey with exact case and no whitespace as stored in open_api_auth.ak.","Trim both sides consistently; consider storing ak in a canonical (lower/upper) form.","Re-check the stored ak value in the admin UI against what the client sends."],"exampleFix":"// before: appKey = \" AK_12345 \"  (whitespace) or \"ak_12345\" (case)\n// after:  appKey = openApiAuth.getAk() exactly, e.g. \"AK_12345\"","handlingStrategy":"validation","validationCode":"// Canonicalize appkey before sending/storing to avoid case/whitespace drift\nString canonical = appkey == null ? null : appkey.trim();\n// store ak in a fixed case (e.g. uppercase) on both sides\nString stored = openApiAuth.getAk().trim();\nif (!canonical.equals(stored)) { /* reject before request */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Store and send appkey trimmed and in a canonical case.","Avoid database collations that match case-insensitively for the ak column.","Re-verify the stored ak value during client onboarding."],"tags":["openapi","auth","credentials","signature"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}