{"record":{"id":"e4b901197e93f840","repo":"dromara/Sa-Token","slug":"30114","errorCode":"30114","errorMessage":"非法 redirect_url: ","messagePattern":"非法 redirect_url: ","errorType":"exception","errorClass":"SaOAuth2ClientModelException","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java","lineNumber":195,"sourceCode":"\t\t\t//       http://sa-token.com/?code=i8vDfbpqBViMe01QoLY1kHROJWYvv9plBtvTZ6kk77KK0e0U4Xj99NPfSZEYjRul\n\t\t\t//\n\t\t\t//  造成了 code 参数劫持\n\t\t\t//  所以此处需要禁止在 url 中出现 @ 字符\n\t\t\t//\n\t\t\t//  这么一刀切的做法，可能会导致一些特殊的正常url也无法通过校验，例如：\n\t\t\t//       http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com/@getInfo\n\t\t\t//\n\t\t\t//  但是为了安全起见，这么做还是有必要的\n\t\t\tthrow new SaOAuth2ClientModelException(\"无效 redirect_url（不允许出现@字符）：\" + url)\n\t\t\t\t\t.setClientId(clientId)\n\t\t\t\t\t.setCode(SaOAuth2ErrorCode.CODE_30113);\n\t\t}\n\n\t\t// 4、是否在[允许地址列表]之中\n\t\tSaClientModel clientModel = checkClientModel(clientId);\n\t\tcheckRedirectUriListNormal(clientModel.allowRedirectUris);\n\t\tif( ! SaStrategy.instance.hasElement.apply(clientModel.allowRedirectUris, url)) {\n\t\t\tthrow new SaOAuth2ClientModelException(\"非法 redirect_url: \" + url)\n\t\t\t\t\t.setClientId(clientId)\n\t\t\t\t\t.setCode(SaOAuth2ErrorCode.CODE_30114);\n\t\t}\n\t}\n\n\t/**\n\t * 校验配置的 allowRedirectUris 是否合规，如果不合规则抛出异常\n\t * @param redirectUriList 待校验的 allow-url 地址列表\n\t */\n\tpublic void checkRedirectUriListNormal(List<String> redirectUriList){\n\t\tcheckRedirectUriListNormalStaticMethod(redirectUriList);\n\t}\n\n\t/**\n\t * 校验配置的 allowRedirectUris 是否合规，如果不合规则抛出异常，静态方法内部实现\n\t * @param redirectUriList 待校验的 allow-url 地址列表\n\t */\n\tpublic static void checkRedirectUriListNormalStaticMethod(List<String> redirectUriList){","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java#L177-L213","documentation":"Thrown when the (query-stripped) redirect_uri is not present in the client's configured allowRedirectUris list (code 30114). sa-token matches the URL against the client's registered allow-list before issuing a code; exact or wildcard-suffix entries match, anything else is rejected as '非法 redirect_url'.","triggerScenarios":"Calling /oauth2/authorize with a redirect_uri whose scheme, host, port, or path differs from every entry in the client's allowRedirectUris (e.g. http vs https, missing port :8000, different path, trailing slash mismatch).","commonSituations":"Client app moved to a new domain or port but allow-url config was not updated; http/https mismatch behind a TLS-terminating proxy; trailing-slash or context-path differences; wildcard entry 'http://client.com/*' not matching a different subdomain.","solutions":["Add the exact redirect_uri to the client's allow-url configuration (sa-token style: putAllowUrl or config in the client register list)","Fix scheme/port/path mismatches in the redirect_uri so it matches an existing allow entry","Use a trailing '*' wildcard entry (e.g. http://client.com/*) only at the end, to cover multiple callback paths"],"exampleFix":"// before\nnew SaClientModel().setClientId(\"1001\").setAllowUrl(\"http://sa-oauth-client.com/callback\");\n// redirect_uri=http://sa-oauth-client.com:8000/callback -> rejected\n// after\nnew SaClientModel().setClientId(\"1001\").setAllowUrl(\"http://sa-oauth-client.com/callback\", \"http://sa-oauth-client.com:8000/callback\");","handlingStrategy":"validation","validationCode":"String stripped = url.split(\"\\\\?\")[0];\nboolean allowed = SaStrategy.instance.hasElement.apply(client.getAllowRedirectUris(), stripped);\nif (!allowed) throw new IllegalArgumentException(\"redirect_uri not in allow list: \" + stripped);","typeGuard":null,"tryCatchPattern":"try { saOAuth2Template.checkRedirectUri(clientId, url); } catch (SaOAuth2ClientModelException e) { if (e.getCode() == 30114) return badRequest(\"redirect_uri not registered\"); throw e; }","preventionTips":["Keep allow-url config in version control and update it in the same change as domain/port migrations","Log the exact rejected URL (query-stripped) to make config diffs obvious"],"tags":["oauth2","redirect-uri","allow-list","configuration"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}