You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在已实现自定义安全的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:21:00