ITfoxtec Identity SAML2生成SAML请求时Destination端口443被移除如何处理
SAML请求Destination字段443端口丢失解决方案
问题根源
.NET的Uri类默认会自动省略HTTPS协议的默认端口443、HTTP协议的默认端口80,你传入带443的地址构造Uri对象后,其标准化输出的AbsoluteUri属性会自动删除端口,而你使用的ITfoxtec Identity SAML2库序列化Destination字段时默认读取Uri的标准化值,所以最终生成的请求就丢失了443端口,无法通过对端IdP的校验。
可行解决方案
方案1:直接修改绑定后的请求XML(最易实现,兼容性最好)
你可以在调用Bind方法生成SAML请求后,直接修改XML根节点的Destination属性为你配置的原始带端口地址,不需要调整原有逻辑:
Saml2Configuration samlconfig = GetSAMLConfig(); // 先取出原始带端口的Destination地址备用 string rawDestination = _appConfiguration["Saml2:SingleSignOnDestination"]; var samlRequest = new Saml2AuthnRequest(samlconfig); samlRequest.AssertionConsumerServiceUrl = new Uri(_appConfiguration["Saml2:AssertionConsumerServiceUrl"]); samlRequest.Destination = new Uri(rawDestination); samlRequest.NameIdPolicy = new NameIdPolicy() { AllowCreate = false, Format = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", SPNameQualifier = _appConfiguration["Saml2:SPNameQualifier"] }; samlRequest.Conditions = new Condition(); samlRequest.Conditions.Items = new List<ITfoxtec.Identity.Saml2.Schemas.Conditions.ICondition>(); samlRequest.Conditions.Items.Add(new ITfoxtec.Identity.Saml2.Schemas.Conditions.AudienceRestriction() { Audiences = new List<Audience>() { new Audience() { Uri = _appConfiguration["Saml2:AllowedAudienceUris"] } } }); var bnd = binding.Bind(samlRequest); // 新增:强制替换Destination为原始带端口的地址 bnd.Xml.DocumentElement.SetAttribute("Destination", rawDestination);
如果你的请求是签名请求,要确保修改XML的操作在签名生成之前完成,若默认Bind方法已经内置签名逻辑,你可以改用方案2。
方案2:自定义SAML请求类覆写序列化逻辑(签名场景适用)
继承官方Saml2AuthnRequest类,重写XML属性序列化逻辑,强制写入你需要的原始Destination地址:
// 自定义请求类 public class PortReservedSaml2AuthnRequest : Saml2AuthnRequest { // 存储原始带端口的Destination地址 public string OriginalDestination { get; set; } public PortReservedSaml2AuthnRequest(Saml2Configuration config) : base(config) { } protected override void WriteXmlAttributes(XmlWriter writer) { base.WriteXmlAttributes(writer); // 序列化时直接写入原始地址,覆盖Uri标准化后的值 if (!string.IsNullOrWhiteSpace(OriginalDestination)) { writer.WriteAttributeString("Destination", OriginalDestination); } } }
替换原有代码中的请求实例即可:
string rawDestination = _appConfiguration["Saml2:SingleSignOnDestination"]; var samlRequest = new PortReservedSaml2AuthnRequest(samlconfig); samlRequest.OriginalDestination = rawDestination; // 其他赋值逻辑保持不变
方案3:全局配置Uri不省略默认端口(.NET 6+适用)
如果你的项目是.NET 6及以上版本,可以在程序启动时加全局配置,让Uri序列化时保留默认端口:
// Program.cs启动时添加 AppContext.SetSwitch("System.Uri.DisableDefaultPortInSerialization", true);
这个配置全局生效,开启后所有Uri对象的AbsoluteUri输出都会保留80/443端口,不需要修改SAML相关代码,适合全项目都需要保留默认端口的场景。
注意事项
- 若使用Redirect绑定方式,修改XML后需要重新生成签名并做URL编码,避免请求校验失败
- 确保替换的Destination地址和你配置的原始值完全一致,不要有多余的转义字符
内容的提问来源于stack exchange,提问作者Bruce
相关产品推荐
相关产品推荐

