引
部署安全的分布式企业报告解决方案是一个极具挑战性的过程。从报告访问到提供重要数据(有时是敏感数据)的数据源,您需要针对如何在报告环境中对用户进行安全的身份验证和授权作出决策。在安全方面,报告是报告链中最薄弱的环节。
所需的安全类型取决于报告环境和已安装的安全系统类型。Microsoft® Windows® Authentication 是用于确保 Microsoft® SQL Server™ 2000 Reporting Services 中的报告安全性的主要系统。Windows Authentication 提供与其他 Microsoft 服务器产品的紧密集成,由于 Reporting Services 是在 Windows Authentication 上设计和测试的,因此它在这个环境中的安全性最高。
然而,在某些情况下,可能需要对 Reporting Services 安全系统进行扩展,以满足企业自定义安全的需要。您可以通过功能丰富的 Reporting Services API 开发平台达到这一目的。本指南将概述 Reporting Services 中的扩展,尤其是安全扩展。您还可以下载适用于 Reporting Services 的示例窗体身份验证扩展,并对它进行深入研究。随后,您可以利用 Reporting Services 安全扩展将自定义安全添加到企业报告解决方案中。
关于本指南
本指南中提供的信息旨在:
• 向您介绍 Reporting Services 安全扩展。
• 确定在 Reporting Services 中使用自定义身份验证和授权的位置和方式。
• 介绍身份验证和授权在 Reporting Services 中的工作方式。
• 介绍窗体身份验证及其实现方式。
• 为您提供了一个可以下载和研究的窗体身份验证示例。
必备知识
本指南未介绍 ASP.NET 安全或窗体身份验证,未提供有关编程或应用程序安全的深层次知识。作为一名期望为 Reporting Services 实现安全扩展的开发人员,您应该对以下一个或多个方面有着深入的了解:
• Microsoft Reporting Services 功能,尤其是身份验证、授权和基于角色的安全。
• Microsoft .NET Framework。
• ASP.NET 和 ASP.NET 安全。
• 窗体身份验证。
• .NET 语言方面的开发经历。本文仅提供用 C# 编写的示例。
要直接了解代码,可以转到“窗体身份验证示例”部分。不过,您可能会发现前面的几部分很有帮助,这些部分介绍了您将使用的某些技术以及如何将这些技术组合在一起使用。
Reporting Services 平台
通过 Reporting Services,可在整个企业中设计、部署和交付报告。从开发人员的角度来看,Reporting Services 通过 .NET Framework 和 Web service 的关键开发平台提供了各种编程机会。Reporting Services 可以通过“随手可用”的方式进行部署,从而可以在任何公司中提供全面的报告解决方案。然而,Reporting Services 的开放式和可扩展编程体系结构使它已不再是一个现成的产品,而更像是开发人员以及最终用户的报告平台。
扩展 Reporting Services
Reporting Services 具有可扩展性。通过托管代码 API,可以开发、安装和管理许多 Reporting Services 组件使用的扩展。可以使用 .NET Framework 创建专用或共享的程序集,并添加新的 Reporting Services 功能以满足日益增长的业务需求。开发人员可通过以下方式扩展 Reporting Services:
• 除了 Reporting Services 当前附带的 Microsoft SQL Server、Oracle 和 OLE DB 提供程序以外,创建其他数据处理扩展。数据处理扩展可用于从您自己特有的数据源中读取数据,并可用于在创建和筛选数据集时并入其他业务逻辑。
• 除了 Reporting Services 当前附带的电子邮件和文件共享交付扩展以外,创建其他交付扩展。交付扩展可用于向传真机、寻呼机、打印机等设备交付报告。
• 除 Reporting Services 已经附带的呈现扩展之外,创建其他呈现扩展。
• 除了 Windows Authentication 扩展(它当前是该产品的默认安全机制)之外,创建其他安全扩展。
如前所述,本指南主要介绍了如何通过窗体身份验证扩展 Reporting Services 的安全系统。
安全扩展
通过 Reporting Services 安全扩展,可以对用户或组进行身份验证和授权,即它使不同的用户能够登录到报告服务器,并根据他们的身份执行不同的任务或操作。默认情况下,Reporting Services 使用基于 Windows 的身份验证扩展,该身份验证扩展使用 Windows 帐户协议验证声称拥有该系统帐户的用户的身份。Reporting Services 使用基于角色的安全系统对用户进行授权。Reporting Services 基于角色的安全模式类似于其他技术的基于角色的安全模式。由于安全扩展基于开放式、可扩展的 API,因此可以在 Reporting Services 中创建新身份验证和授权扩展。以下是使用基于窗体的身份验证和授权的安全扩展实现的典型示例:
1.用户尝试通过输入 URL 来访问 Report Manager,然后被重定向到一个为客户端应用程序收集用户凭据的窗体。
2.该用户将凭据提交给窗体。
3.通过 LogonUser 方法将该用户的凭据提交给 Reporting Services Web service。
4.Web service 调用客户提供的安全扩展,并验证自定义安全机构中是否存在该用户名和密码。
5.进行身份验证时,Web service 将创建身份验证票据(称作“Cookie”),管理该票据,并验证该用户的角色能否访问 Report Manager 的主页。
6.Web service 将 Cookie 返回给浏览器,并在 Report Manager 中显示相应的用户界面。
7.身份验证结束后,浏览器向 Report Manager 发出请求,同时在 HTTP 标头中传输此 Cookie。这些请求是为响应 Report Manager 应用程序中的用户操作而发出的。
8.该 Cookie 连同请求的用户操作在 HTTP 标头中一起被传输到 Web service。
9.Cookie 将接受验证,如果它有效,报告服务器将从报告服务器数据库中返回与请求操作相关的安全描述符和其他信息。
10.如果 Cookie 有效,报告服务器将调用安全扩展,以检查该用户是否有权执行特定的操作。
11.如果该用户已被授权,报告服务器将执行请求的操作,并将控制返回给调用方。
12.该用户经过身份验证后,对报告服务器的 URL 访问将使用相同的 Cookie。该 Cookie 在 HTTP 标头中传输。
13.用户继续在报告服务器上请求操作,直至会话结束。
何时实现安全扩展
Microsoft 建议您尽可能地使用 Windows Authentication。不过,但在以下两种情况下,应使用 Reporting Services 的自定义身份验证和授权:
• Internet 或 Extranet 应用程序未使用或无法使用 Windows 帐户。
• 您具有自定义的用户和角色,并且需要在 Reporting Services 中提供匹配的授权方案。
安全扩展 API
下表列出了安全扩展的可用接口和类。
有关安全扩展 API 的各种接口和类的详细信息,请参阅 Reporting Services 联机丛书。
Reporting Services 中的身份验证
身份验证是建立用户身份权限的过程。有许多方法可用于用户身份验证。最常用的方法是使用密码。实现窗体身份验证时,应使用这样的实现:请求用户提供凭据(一般通过要求输入登录名和密码的某种界面),然后根据用户存储(例如,数据库表或配置文件)验证用户。如果凭据无法得到验证,身份验证进程将失败,用户将获取匿名身份。
在 Reporting Services 中,Windows 操作系统通过集成的安全性或通过用户凭据的显式接收和验证来处理用户的身份验证。可对 Reporting Services 中的自定义身份验证进行开发,使之支持其他身份验证方案。为此,可使用安全扩展接口 IAuthenticationExtension。所有扩展都继承于 IExtension,它是报告服务器部署和使用的任何扩展的基本接口。IExtension 和 IAuthenticationExtension 是 Microsoft.ReportingServices.Interfaces 命名空间的成员。
LogonUser 方法是 Reporting Services 中所有身份验证的核心。可使用它将用户凭据传递给报告服务器进行验证。基础安全扩展实现包含自定义身份验证代码的 IAuthenticationExtension.LogonUser。在窗体身份验证示例(将在本指南后面部分介绍)中,LogonUser 根据提供的凭据和数据库中的自定义用户存储区执行身份验证检查。在窗体身份验证示例中,它类似于以下过程:
在 AuthenticationExtension.cs(窗体身份验证示例)中
public bool LogonUser(string userName, string password, string authority)
{
return AuthenticationUtilities.VerifyPassword(userName, password);
}
在 AuthenticationUtilities.cs(窗体身份验证示例)中
internal static bool VerifyPassword(string suppliedUserName,
string suppliedPassword)
{
bool passwordMatch = false;
// 基于用户名从数据库中获取 Salt 和密