.NET Core连接STS签发令牌认证的WCF服务方案咨询
.NET Core连接采用STS IssuedToken认证的WCF服务可行方案
由于.NET Core官方WCF客户端对消息安全场景的支持有限,针对你的STS IssuedTokenOverTransport认证场景,可通过手动实现STS令牌获取+自定义SOAP请求的方式完成对接,以下是具体方案:
核心思路
- 绕过.NET Core WCF客户端的限制,直接向STS服务发送请求获取SAML令牌
- 将获取到的SAML令牌添加到目标WCF服务的SOAP安全头中
- 通过HttpClient发送带客户端证书和安全头的SOAP请求完成服务调用
具体实现步骤
1. 加载客户端证书
首先加载用于TLS认证的X509证书:
var clientCert = new X509Certificate2( @"XXX.pfx", "123", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet );
2. 手动向STS请求SAML令牌
构造符合STS要求的SOAP请求,通过HttpClient发送请求并解析返回的SAML令牌(以WSO2 Carbon STS为例):
private static string GetSamlTokenFromSts( string stsUrl, string username, string password, X509Certificate2 clientCert) { // 构造STS的SOAP请求(需根据STS的WSDL调整格式) var soapRequest = $@"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:wsa=""http://www.w3.org/2005/08/addressing"" xmlns:wst=""http://docs.oasis-open.org/ws-sx/ws-trust/200512""> <soapenv:Header> <wsa:Action>http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</wsa:Action> <wsa:To>{stsUrl}</wsa:To> </soapenv:Header> <soapenv:Body> <wst:RequestSecurityToken> <wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType> <wst:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1</wst:TokenType> <wsp:AppliesTo xmlns:wsp=""http://schemas.xmlsoap.org/ws/2004/09/policy""> <wsa:EndpointReference> <wsa:Address>https://XXXXX/services/Secured</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <wst:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</wst:KeyType> </wst:RequestSecurityToken> </soapenv:Body> </soapenv:Envelope>"; var handler = new HttpClientHandler(); handler.ClientCertificates.Add(clientCert); // 设置Basic认证(对应STS绑定中的UserNameOverTransport) var authBytes = Encoding.ASCII.GetBytes($"{username}:{password}"); var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authBytes)); using (var client = new HttpClient(handler)) { client.DefaultRequestHeaders.Authorization = authHeader; client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/soap+xml")); var content = new StringContent(soapRequest, Encoding.UTF8, "application/soap+xml"); var response = client.PostAsync(stsUrl, content).Result; response.EnsureSuccessStatusCode(); var responseXml = response.Content.ReadAsStringAsync().Result; var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(responseXml); // 解析XML获取SAML令牌节点 var nsManager = new XmlNamespaceManager(xmlDoc.NameTable); nsManager.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); var tokenNode = xmlDoc.SelectSingleNode("//wsse:BinarySecurityToken", nsManager); return tokenNode?.InnerText; } }
3. 构造并发送目标WCF服务请求
将获取到的SAML令牌添加到SOAP安全头中,发送请求到目标服务:
private static void CallWcfService( string serviceUrl, string samlToken, X509Certificate2 clientCert) { // 构造目标服务的SOAP请求(需根据服务WSDL调整参数) var soapRequest = $@"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:guv=""GuvenliOdemeServis""> <soapenv:Header> <wsse:Security xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:wsu=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd""> <wsse:BinarySecurityToken EncodingType=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"" ValueType=""http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"" wsu:Id=""SAMLToken"">{samlToken}</wsse:BinarySecurityToken> </wsse:Security> </soapenv:Header> <soapenv:Body> <guv:EOdemeSaticiKaydet> <!-- 替换为实际请求参数 --> <!-- <guv:param1>value1</guv:param1> --> </guv:EOdemeSaticiKaydet> </soapenv:Body> </soapenv:Envelope>"; var handler = new HttpClientHandler(); handler.ClientCertificates.Add(clientCert); using (var client = new HttpClient(handler)) { client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml")); var content = new StringContent(soapRequest, Encoding.UTF8, "text/xml"); var response = client.PostAsync(serviceUrl, content).Result; response.EnsureSuccessStatusCode(); var responseXml = response.Content.ReadAsStringAsync().Result; // 解析响应结果,处理业务逻辑 Console.WriteLine("服务调用响应:" + responseXml); } }
4. 主函数调用流程
static void Main(string[] args) { var username = "your_username"; var password = "your_password"; var stsUrl = "https://XXXX/services/wso2carbon-sts"; var serviceUrl = "https://XXXXX/services/Secured"; // 设置TLS版本匹配.NET Framework客户端 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; var clientCert = new X509Certificate2( @"XXX.pfx", "123", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet ); // 获取SAML令牌 var samlToken = GetSamlTokenFromSts(stsUrl, username, password, clientCert); if (string.IsNullOrEmpty(samlToken)) { Console.WriteLine("获取STS令牌失败"); return; } // 调用目标WCF服务 CallWcfService(serviceUrl, samlToken, clientCert); }
注意事项
- SOAP请求格式需严格匹配STS和目标服务的WSDL定义,可使用抓包工具获取.NET Framework客户端的请求作为参考
- 解析XML时需正确处理命名空间,避免节点找不到的问题
- 客户端证书加载时若遇到权限问题,可调整
X509KeyStorageFlags参数 - 确保TLS版本与服务端要求一致(示例中为TLS1.2)
内容的提问来源于stack exchange,提问作者muhammetsahin
相关产品推荐
相关产品推荐

