dromara/Sa-Token · error · SaSsoException
CODE_30002
CODE_30002
Error message
非法redirect:{url} What it means
Final-stage rejection in checkRedirectUrl: the URL is well-formed and '@'-free but does not match any entry in the client's configured allow-url list. The server only issues tickets to pre-registered callback addresses to prevent ticket leakage to arbitrary hosts.
Source
Thrown at sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoServerTemplate.java:455
// 那么这个url就会绕过 allow-url 的校验,ticket 被下发到了第三方服务器地址:
// http://sa-token.com/?ticket=i8vDfbpqBViMe01QoLY1kHROJWYvv9plBtvTZ6kk77KK0e0U4Xj99NPfSZEYjRul
//
// 造成了ticket 参数劫持
// 所以此处需要禁止在 url 中出现 @ 字符
//
// 这么一刀切的做法,可能会导致一些特殊的正常url也无法通过校验,例如:
// http://sa-sso-server.com:9000/sso/auth?redirect=http://sa-sso-client1.com:9003/@getInfo
//
// 但是为了安全起见,这么做还是有必要的
throw new SaSsoException("无效redirect(不允许出现@字符):" + url).setCode(SaSsoErrorCode.CODE_30001);
}
// 4、判断是否在 [ 允许的地址列表 ] 之中
String allowUrlString = getClientNotNull(client).getAllowUrl();
List<String> allowUrlList = Arrays.asList(allowUrlString.replaceAll(" ", "").split(","));
checkAllowUrlList(allowUrlList);
if( ! SaStrategy.instance.hasElement.apply(allowUrlList, url) ) {
throw new SaSsoException("非法redirect:" + url).setCode(SaSsoErrorCode.CODE_30002);
}
// 校验通过 √
}
/**
* 校验配置的 AllowUrl 是否合规,如果不合规则抛出异常
* @param allowUrlList 待校验的 allow-url 地址列表
*/
public void checkAllowUrlList(List<String> allowUrlList){
checkAllowUrlListStaticMethod(allowUrlList);
}
/**
* 校验配置的 AllowUrl 是否合规,如果不合规则抛出异常
* @param allowUrlList 待校验的 allow-url 地址列表
*/
public static void checkAllowUrlListStaticMethod(List<String> allowUrlList){View on GitHub (pinned to ac2c7f6e94)
Solutions
- Add the exact redirect origin to the client's allow-url on the sso-server, e.g. http://client.com/sso/login or http://client.com/*
- Match the port and path exactly — http://client.com and http://client.com:8080 are different entries
- Use a trailing * only at the end (e.g. http://client.com/*) for path-level wildcards
Example fix
# application.yml (sso-server)
# before
sa-token:
sso:
server:
clients:
- client: app1
allow-url: http://old-domain.com/sso/login
# after
sa-token:
sso:
server:
clients:
- client: app1
allow-url: http://old-domain.com/sso/login,http://new-domain.com:8080/sso/login Defensive patterns
Strategy: validation
Validate before calling
List<String> allow = Arrays.asList(scm.getAllowUrl().replaceAll(" ", "").split(","));
if(!SaStrategy.instance.hasElement.apply(allow, redirect)) {
// fail with your own message listing the allowed origins
} Prevention
- Keep allow-url in sync with deployment domains; review it whenever a client moves hosts
- Include scheme+port in every allow entry; they are part of the match
When it happens
Trigger: redirect=http://newhost.com/sso/login while the client's allow-url config contains only other domains; the URL differs from the allowed entry by port, path, or trailing slash; allow-url uses '*' in a way that does not actually cover this URL.
Common situations: New deployment on a different domain/port forgotten in allow-url; allow-url copied with a typo; subdomain not covered because the pattern ends at the parent domain; spaces in the comma list (they are stripped, but verify).
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/1c83241c27cea8d8.
Report an issue: GitHub.