ASP.NET OpenIdConnect重定向URI格式错误问题求助(西里尔域名场景)
解决OpenIdConnectHandler处理西里尔域名Punycode重定向URI的格式问题
我之前也遇到过类似的国际化域名在OpenID Connect中触发重定向URI校验失败的问题,结合你的场景给你几个可行的解决方向:
1. 检查客户端配置的重定向URI白名单
首先要确认你的OIDC客户端(对应client_id=RosgrantService)配置里,已经把Punycode格式的完整重定向URI(也就是http://xn----7sbhbm9amwu.xn--p1ai:5002/signin-oidc)添加到允许的重定向URI列表中。很多OIDC服务端会做严格的白名单匹配,哪怕Punycode和原西里尔域名是等价的,也必须显式配置Punycode版本的URI,不能只填原文域名。
2. 手动控制域名的Punycode转换与URI编码
有时候OIDC中间件的自动编码逻辑可能对IDN(国际化域名)处理不彻底,你可以在发起授权请求前手动完成转换和编码:
比如在.NET环境下,用IdnMapping类来转Punycode:
var idnConverter = new IdnMapping(); // 将西里尔域名转成Punycode string punycodeHost = idnConverter.GetAscii("грант-лев.рф"); // 拼接完整的重定向URI string rawRedirectUri = $"http://{punycodeHost}:5002/signin-oidc"; // 确保URI按照application/x-www-form-urlencoded标准编码 string encodedRedirectUri = Uri.EscapeDataString(rawRedirectUri);
用这个手动编码后的URI发起授权请求,能避免中间件自动转换时的异常。
3. 自定义OpenIdConnectHandler的校验逻辑
如果上述方法都无效,可能需要重写OpenIdConnectHandler的重定向URI校验逻辑,兼容Punycode格式:
public class CustomOpenIdConnectHandler : OpenIdConnectHandler { public CustomOpenIdConnectHandler(IOptionsMonitor<OpenIdConnectOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { } protected override async Task<AuthenticateResult> ValidateRedirectUriAsync(OpenIdConnectMessage message) { // 先执行原有校验逻辑 var baseResult = await base.ValidateRedirectUriAsync(message); // 如果原有校验失败,且URI包含Punycode标识(xn--),则执行自定义校验 if (baseResult.Failed && !string.IsNullOrEmpty(message.RedirectUri) && message.RedirectUri.Contains("xn--")) { try { var redirectUri = new Uri(message.RedirectUri); // 这里替换成你的白名单校验逻辑,比如检查Host是否在允许的Punycode列表中 if (IsAllowedPunycodeHost(redirectUri.Host)) { return AuthenticateResult.Success(); } } catch (UriFormatException) { // 保留原有错误逻辑 return baseResult; } } return baseResult; } private bool IsAllowedPunycodeHost(string host) { // 这里添加你的允许列表判断,比如: return host == "xn----7sbhbm9amwu.xn--p1ai"; } }
然后在Startup中替换默认的Handler:
services.AddAuthentication() .AddOpenIdConnect(options => { // 其他配置... options.ForwardDefaultSelector = context => typeof(CustomOpenIdConnectHandler).FullName; });
4. 确认OIDC服务端的IDN支持
最后要检查你的OIDC服务端(比如IdentityServer、Keycloak等)是否开启了IDN支持。有些服务端默认会禁用对Punycode URI的支持,需要在服务端配置中开启相关选项,比如IdentityServer中可以检查是否允许非ASCII域名的重定向URI。
额外注意事项
- 测试时可以直接用Punycode格式的域名访问你的应用,确认应用本身能正常解析这个域名,排除DNS层面的问题;
- 确保整个请求链路中,客户端、中间件、服务端的编码逻辑一致,避免出现URI多次编码或解码的情况。
内容的提问来源于stack exchange,提问作者Lev Nikolaevich




