.NET Core调用SSRS报告遇NTLM认证未授权错误求解决
问题概述
在.NET Core应用中生成SSRS报告时,遭遇NTLM认证异常:
The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'NTLM'.
移除凭证、使用BasicHttpSecurityMode.None搭配HttpClientCredentialType.None时程序可正常运行,但业务要求必须为服务添加凭证。尝试设置ProxyCredentialType为Ntlm、替换HttpClientCredentialType为Windows均无效,且.NET Core中找不到.NET Framework方案提及的web.config或配置编辑器。
已尝试的无效操作
- 设置
ProxyCredentialType = HttpProxyCredentialType.Ntlm,仍触发原认证错误 - 替换
HttpClientCredentialType.Ntlm为HttpClientCredentialType.Windows,触发新错误:
System.ServiceModel.Security.MessageSecurityException: The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'NTLM'
可行修复方案
1. 强制绑定仅使用NTLM认证
在绑定配置中添加ExtendedProtectionPolicy禁用Negotiate(Kerberos回退机制),确保客户端只发送NTLM认证头:
var binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly); binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm; binding.MaxReceivedMessageSize = 10485760; // 10MB限制 // 关键:禁用Extended Protection,强制使用纯NTLM binding.Security.Transport.ExtendedProtectionPolicy = new System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy(System.Security.Authentication.ExtendedProtection.ProtectionPolicy.None); var rsExec = new ReportExecutionServiceSoapClient(binding, new EndpointAddress(SSRSReportExecutionUrl)); // 注意:域环境下替换"."为实际域名,本地账户保留"." var clientCredentials = new NetworkCredential(SSRSUsername, SSRSPassword, "YOUR-DOMAIN-OR-MACHINE-NAME"); if (rsExec.ClientCredentials != null) { // 调整模拟级别为Delegation(部分场景需要) rsExec.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation; rsExec.ClientCredentials.Windows.ClientCredential = clientCredentials; }
2. 用appsettings.json管理WCF配置(.NET Core友好)
.NET Core支持通过配置文件管理WCF绑定,避免硬编码。在appsettings.json中添加:
{ "SSRS": { "ReportExecutionEndpoint": "http://your-ssrs-server/ReportServer/ReportExecution2005.asmx", "BindingSettings": { "SecurityMode": "TransportCredentialOnly", "ClientCredentialType": "Ntlm", "MaxReceivedMessageSize": 10485760 } } }
然后在代码中读取配置并初始化客户端:
var ssrsConfig = Configuration.GetSection("SSRS").Get<SsrsConfig>(); var binding = new BasicHttpBinding(); binding.Security.Mode = Enum.Parse<BasicHttpSecurityMode>(ssrsConfig.BindingSettings.SecurityMode); binding.Security.Transport.ClientCredentialType = Enum.Parse<HttpClientCredentialType>(ssrsConfig.BindingSettings.ClientCredentialType); binding.MaxReceivedMessageSize = ssrsConfig.BindingSettings.MaxReceivedMessageSize; // 同样添加ExtendedProtectionPolicy设置 binding.Security.Transport.ExtendedProtectionPolicy = new System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy(System.Security.Authentication.ExtendedProtection.ProtectionPolicy.None); var rsExec = new ReportExecutionServiceSoapClient(binding, new EndpointAddress(ssrsConfig.ReportExecutionEndpoint)); // 凭证设置同方案1
(需定义对应SsrsConfig类来绑定配置)
3. 检查SSRS服务器端配置
确保SSRS服务器的Web服务已正确启用NTLM:
- 打开IIS管理器,定位到ReportServer站点
- 进入身份验证模块,启用Windows身份验证
- 点击Windows身份验证的"提供程序",确保
NTLM在列表中且优先级高于Negotiate - 打开SSRS配置管理器,进入Web服务URL,确认身份验证设置中已勾选
NTLM
4. 本地账户场景的额外处理
如果使用SSRS服务器的本地账户(非域账户):
- 确保客户端与服务器在同一信任网络
- 在服务器上禁用UAC远程限制:通过组策略编辑器(
gpedit.msc),进入计算机配置>Windows设置>安全设置>本地策略>安全选项,设置本地账户的管理员批准模式为"已禁用" NetworkCredential的域名参数使用服务器的完整机器名,而非"."
内容的提问来源于stack exchange,提问作者Merna Mustafa

