如何在已实现自定义安全的SSRS 2016中调用V1.0 REST API(非SOAP)
解决SSRS 2016自定义安全扩展下的凭据传递问题
兄弟,我一看就知道你踩了自定义安全扩展的适配坑——之前用CredentialCache那套逻辑是针对Windows集成认证的,启用自定义安全后这套直接失效了,得换个思路来搞!下面给你一步步拆解解决方案:
1. 先明确你的自定义安全认证模式
首先得搞清楚你实现的自定义安全是哪种类型:
- 如果是表单认证:需要先模拟登录请求拿到认证Cookie,后续所有报表请求都带着这个Cookie维持会话
- 如果是自定义令牌认证:要生成符合扩展约定的令牌,放在请求头或者指定参数里传递
2. 表单认证场景的代码示例
假设你的自定义登录页面是/ReportServer/Logon.aspx(ASP.NET表单类型),代码可以这么调整:
using System.Net; using System.IO; using System.Collections.Specialized; using System.Linq; using System.Text.RegularExpressions; // 第一步:初始化Cookie容器,用来维持会话上下文 var cookieJar = new CookieContainer(); // 先请求登录页面,提取ASP.NET表单必备的隐藏字段(__VIEWSTATE、__VIEWSTATEGENERATOR) var loginPageRequest = (HttpWebRequest)WebRequest.Create("http://你的报表服务器地址/ReportServer/Logon.aspx"); loginPageRequest.CookieContainer = cookieJar; using (var loginPageResponse = (HttpWebResponse)loginPageRequest.GetResponse()) using (var reader = new StreamReader(loginPageResponse.GetResponseStream())) { var pageContent = reader.ReadToEnd(); // 用正则提取隐藏字段值 var viewState = Regex.Match(pageContent, @"<input type=""hidden"" name=""__VIEWSTATE"" id=""__VIEWSTATE"" value=""(.*?)"" />").Groups[1].Value; var viewStateGenerator = Regex.Match(pageContent, @"<input type=""hidden"" name=""__VIEWSTATEGENERATOR"" id=""__VIEWSTATEGENERATOR"" value=""(.*?)"" />").Groups[1].Value; // 第二步:构造登录请求参数 var postParams = new NameValueCollection { ["UserName"] = "你的用户名", ["Password"] = "你的密码", ["__VIEWSTATE"] = viewState, ["__VIEWSTATEGENERATOR"] = viewStateGenerator, ["LoginButton"] = "登录" // 按钮的name值,需对应登录页面源码中的按钮name }; // 转换参数为POST请求格式的字节数组 var postDataBytes = System.Text.Encoding.UTF8.GetBytes( string.Join("&", postParams.AllKeys.Select(k => $"{Uri.EscapeDataString(k)}={Uri.EscapeDataString(postParams[k])}")) ); // 发送登录请求 var authRequest = (HttpWebRequest)WebRequest.Create("http://你的报表服务器地址/ReportServer/Logon.aspx"); authRequest.Method = "POST"; authRequest.ContentType = "application/x-www-form-urlencoded"; authRequest.ContentLength = postDataBytes.Length; authRequest.CookieContainer = cookieJar; using (var requestStream = authRequest.GetRequestStream()) { requestStream.Write(postDataBytes, 0, postDataBytes.Length); } // 验证登录是否成功 using (var authResponse = (HttpWebResponse)authRequest.GetResponse()) { if (authResponse.StatusCode != HttpStatusCode.OK) { throw new Exception("登录失败,请检查用户名密码或表单参数"); } } } // 第三步:用已认证的Cookie访问报表服务 var reportServerUri = new Uri("http://你的报表服务器地址/ReportServer"); var reportRequest = (HttpWebRequest)WebRequest.Create(reportServerUri); reportRequest.CookieContainer = cookieJar; // 后续即可正常处理报表请求,比如获取报表列表、执行报表等
3. 自定义令牌认证场景的代码示例
如果你的自定义安全是基于令牌的(比如自己实现了令牌生成逻辑),代码会更简洁:
using System.Net; // 第一步:根据自定义安全扩展的逻辑获取认证令牌 // 比如调用扩展提供的登录接口,传入用户名密码拿到令牌 var authToken = GetCustomAuthToken("你的用户名", "你的密码"); // 第二步:构造报表请求,在请求头中带上令牌(格式需和扩展约定一致) var reportServerUri = new Uri("http://你的报表服务器地址/ReportServer"); var reportRequest = (HttpWebRequest)WebRequest.Create(reportServerUri); reportRequest.Headers.Add("Authorization", $"CustomToken {authToken}"); // 示例格式,需替换为你的扩展约定格式 // 后续处理报表请求即可
4. 关键注意事项
- 会话连续性:自定义安全依赖Cookie或令牌维持会话,表单认证必须用同一个
CookieContainer,令牌认证要确保每次请求都携带有效令牌 - 适配扩展细节:不同的自定义安全扩展可能有特殊要求,比如加密密码、特定请求头,需结合你实现
IAuthenticationExtension时的逻辑调整 - 权限验证:即使认证通过,也要确保该用户在SSRS中拥有对应报表的访问权限,否则仍会报错
之前的CredentialCache是专为Windows集成认证设计的,自定义安全场景下完全不兼容,必须换成上面的适配方案!
内容的提问来源于stack exchange,提问作者user3292410
相关产品推荐
相关产品推荐

