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 和密码。
// 请参阅“How To:Use DPAPI (Machine Store) from ASP.NET”、“How To:
// Use DPAPI (User Store) from Enterprise Services”和“How To:
// Create a DPAPI Library”,以了解有关如何使用
// DPAPI 安全地存储连接字符串的详细信息。
SqlConnection conn = new SqlConnection(
"Server=localhost;" +
"Integrated Security=SSPI;" +
"database=UserAccounts");
SqlCommand cmd = new SqlCommand("LookupUser", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter sqlParam = cmd.Parameters.Add("@userName",
SqlDbType.VarChar,
255);
sqlParam.Value = suppliedUserName;
try
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
reader.Read(); // 跳转到唯一行
// 从返回的数据流返回输出参数
string dbPasswordHash = reader.GetString(0);
string salt = reader.GetString(1);
reader.Close();
// 现在采用用户输入的 Salt 和密码
// 并将它们串联在一起。
string passwordAndSalt = String.Concat(suppliedPassword, salt);
// 现在对它们进行哈希操作
string hashedPasswordAndSalt =
FormsAuthentication.HashPasswordForStoringInConfigFile(
passwordAndSalt,
"SHA1");
// 现在验证它们。如果它们相等,则返回 true
passwordMatch = hashedPasswordAndSalt.Equals(dbPasswordHash);
}
catch (Exception ex)
{
throw new Exception("Exception verifying password. " +
ex.Message);
}
finally
{
conn.Close();
}
return passwordMatch;
}
身份验证流程
Reporting Services Web service 提供自定义身份验证,以便 Report Manager 和报告服务器能够进行窗体身份验证。
Reporting Services Web service 的 LogonUser 方法用于将凭据提交给报告服务器,以进行身份验证。Web service 使用 HTTP 标头将身份验证票据(称为“Cookie”)从服务器传递到客户端,以响应已验证的登录请求。
下图描述了当使用配置为使用自定义身份验证扩展的报告服务器来部署您的应用程序时,对要访问 Web service 的用户进行身份验证的方法。
图 2如图 2 所示,身份验证进程如下:
|
1.
|
客户端应用程序调用 Web service 方法 LogonUser 对用户进行身份验证。
|
|
2.
|
Web service 调用安全扩展(具体而言,是指实现 IAuthenticationExtension 的类)的 LogonUser 方法。
|
|
3.
|
LogonUser 的实现验证用户存储或安全机构中的用户名和密码。
|
|
4.
|
身份验证成功后,Web service 将创建 Cookie 并针对会话对其进行管理。
|
|
5.
|
Web service 通过 HTTP 标头将身份验证票据返回给调用的应用程序。
|
Web service 通过安全扩展成功对用户进行身份验证后,将生成一个 Cookie,用于随后的请求。由于报告服务器没有安全机构,因此该 Cookie 不会一直保存在自定义安全机构中。Cookie 从 Web service 方法 LogonUser 返回,并用于随后的 Web service 方法调用以及 URL 访问。
安全:为了避免在传输过程中泄露 Cookie,应使用安全套接字层 (SSL) 加密安全地传输从 LogonUser 返回的 Cookie。
如果在安装了自定义安全扩展的情况下通过 URL 访问来访问报告服务器,则 Internet 信息服务 (IIS) 和 ASP.NET 将自动管理身份验证票据的传输。如果通过 SOAP API 访问报告服务器,则代理类的实现必须包含对身份验证票据管理的附加支持。有关使用 SOAP API 和管理身份验证票据的详细信息,请参阅本指南后面的“将 Web service 用于自定义安全”。
Reporting Services 中的身份验证
授权是指决定是否为某一身份授予请求类型的访问权限(访问报告服务器数据库中的给定资源的权限)的过程。Reporting Services 使用基于角色的授权体系结构,即,基于应用程序中的用户角色授予用户访问给定资源的权限。Reporting Services 的安全扩展包含授权组件(一旦用户在报告服务器上得到验证,该授权组件便用于授予用户权限)的实现。当用户试图通过 SOAP API 和通过 URL 访问对系统或报告服务器项目执行操作时,授权便被调用。为此,可以使用安全扩展接口 IAuthorizationExtension。如前所述,所有扩展都继承于 IExtension,它是部署的任何扩展的基本接口。IExtension 和 IAuthorizationExtension 是 Microsoft.ReportingServices.Interfaces 命名空间的成员。
在授权中,任何自定义安全实现的关键是访问权检查,该检查在方法 CheckAccess 中进行。每当用户试图在报告服务器上进行操作时,CheckAccess 便会被调用。CheckAccess 方法将针对每种操作类型进行重载。对于文件夹操作,访问权检查的示例可能如下所示:
// 针对文件夹操作重载
public bool CheckAccess(
string userName,
IntPtr userToken,
byte[] secDesc,
FolderOperation requiredOperation)
{
// 如果用户是管理员,则允许无限制访问。
if (userName == m_adminUserName)
return true;
AceCollection acl = DeserializeAcl(secDesc);
foreach(AceStruct ace in acl)
{
if (userName == ace.PrincipalName)
{
foreach(FolderOperation aclOperation in
ace.FolderOperations)
{
if (aclOperation == requiredOperation)
return true;
}
}
}
return false;
}
报告服务器通过传入登录用户的名称、用户令牌、操作项目的安全描述符和请求的操作来调用 CheckAccess 方法。此处。您将检查用户名的安全描述符和完成请求的适当权限,然后返回 true,表明访问权限已授予,或者返回 false,表明访问权限被拒绝。