本页内容
|
目标 |
|
适用范围 |
|
如何使用本章内容 |
|
摘要 |
|
您必须了解的背景知识 |
|
创建一个简单的 Web 服务 |
|
将 Web 服务虚拟目录配置为需要有客户端证书 |
|
创建一个自定义帐户以运行服务组件 |
|
为自定义帐户请求一个客户端证书 |
|
使用浏览器测试客户端证书 |
|
将客户端证书导出到一个文件中 |
|
开发用于调用该 Web 服务的服务组件 |
|
配置和安装服务组件 |
|
开发一个 Web 应用程序以调用该服务组件 |
|
其他资源 |
目标
本章的作用是:
• |
使用服务组件,可让 Web 应用程序调用以下 Web 服务:要求客户端使用客户端证书进行身份验证。 |
返回页首
适用范围
本章适用于以下产品和技术:
• |
Microsoft® Windows® XP 或 Windows 2000 Server (Service Pack 3) 以及更高版本的操作系统 |
• |
Microsoft Internet 信息服务 5.0 |
• |
Microsoft 证书服务(如果您需要生成自己的客户端证书) |
• |
Microsoft .NET Framework 版本 1.0 (Service Pack 2) |
• |
Microsoft SQL Server™2000 (Service Pack 2) 以及更高版本 |
• |
Microsoft Visual C#® .NET |
返回页首
如何使用本章内容
若要学好本章内容:
• |
您必须具有使用 Visual C# .NET 和 Microsoft Visual Studio® .NET 的经验。 |
• |
您必须具有使用 ASP.NET 开发 Web 应用程序的经验。 |
• |
您必须具有开发和实现在企业服务 (COM+) 上下文中运行的服务组件的经验。 |
• |
您必须具有开发和实现 Windows 服务的经验。 |
• |
您必须知道如何使用 Windows 管理工具来创建 Windows 用户帐户。 |
• |
如果您想生成新的客户端证书,则必须能够访问某个证书颁发机构 (CA),如 Microsoft 证书服务。 |
• |
如果您不希望生成自己的证书,则必须决定将从哪个商业证书颁发机构申请客户端证书。某些证书颁发机构 (CA) 会就此服务收费。 |
• |
您必须具有一台安装了 SSL 证书的 Web 服务器。有关详细信息,请参见如何在 Web 服务器上设置 SSL。 |
• |
阅读第 2 章 ASP.NET 应用程序的安全模型,其中介绍了客户端证书,并将其与其他形式的身份验证进行了比较。 |
返回页首
摘要
客户端证书为 Web 应用程序提供了一种非常好的身份验证机制。浏览器或其他客户端应用程序必须先提供有效的身份验证,然后才能获得应用程序访问权限,这使得客户端不必提供用户名和密码。因此,在创建供其他客户端应用程序访问的安全 Web 服务时,客户端的证书就显得特别有用。
本章介绍如何调用一个根据配置需要从 Web 应用程序获得客户端证书的 Web 服务。
返回页首
您必须了解的背景知识
如果您使用客户端证书,您的应用程序也会受益于客户端应用程序和 Web 服务之间创建的安全通道(使用安全套接字层 [SSL])。这样您就可以安全地在 Web 服务之间传送保密信息。SSL 确保消息的完整性和机密性。
注意:本章中的信息还适用于 ASP.NET 和 IIS 中承载的远程组件。
为什么使用服务组件?
本章所介绍的解决方案使用一个按配置应在企业服务服务器应用程序中运行的服务组件(使用自定义的服务帐户)。ASP.NET Web 应用程序调用该服务组件,而该服务组件又调用 Web 服务(传递客户端证书)。图 1 中显示了这一解决方案配置。
图 1
ASP.NET 调用服务组件以调用 Web 服务
这种配置是为了确保系统在与 Web 服务通信时能够访问用户配置文件。这是初始 SSL 握手所要求的。
注意:用于运行 Web 应用程序的 ASPNET 帐户具有“拒绝交互登录”权限,它禁止用户使用此帐户进行交互登录。结果,此帐户没有用户配置文件。
不要为 ASPNET 帐户(或任何用于运行 Web 应用程序的帐户)授予交互登录的权限。在配置运行 Web 应用程序的帐户时始终要遵循最少权限原则,而且为它们授予尽可能少的权限。有关详细信息,请参见本指南的如何创建自定义帐户以运行 ASP.NET。
为什么需要用户配置文件?
当您请求得到一项要求客户端证书的 Web 服务时,在客户端和服务器之间就会进行 SSL 握手。交换的一些组件有服务器证书、客户端证书以及客户端生成的预主密钥。以后可在协议中使用此密钥来生成主密钥。
为使服务器确认证书提供者就是实际的私钥持有者,客户端必须使用私钥加密预主密钥,并将加密的预主密钥发送到服务器。为使系统能够访问客户端的私钥以签名预主密钥,它必须访问客户端密钥存储中的私钥。密钥存储位于客户端的配置文件(必须加载)中。
注意:在本章中,将 Web 服务计算机(它承载 Web 服务)称为“WSServer”;而将 Web 服务客户端计算机(它承载客户端 ASP.NET Web 应用程序和服务组件)称为“WSClient”。
返回页首
创建一个简单的 Web 服务
• |
在 Web 服务主机上创建一个简单的 Web 服务
1. |
启动 Visual Studio .NET,创建一个新的名为 SecureMath 的 C# ASP.NET Web 服务应用程序。 |
2. |
将 service1.asmx 重命名为 math.asmx。 |
3. |
打开 math.asmx.cs,并将 Service1 类重命名为 math。 |
4. |
将下面的 Web 方法添加到 math 类。 [WebMethod]
public long Add(long operand1, long operand2)
{
return (operand1 + operand2);
}
|
5. |
在“生成”菜单上,单击“生成解决方案”以创建 Web 服务。 |
|
返回页首
将 Web 服务虚拟目录配置为需要有客户端证书
此过程使用 Internet 信息服务为 SSL 配置 Web 服务的虚拟目录并且要求使用证书。
本过程假设您在 Web 服务器上安装了有效的证书。有关安装 Web 服务器证书的详细信息,请参见本指南中的如何在 Web 服务器上设置 SSL。
• |
将 Web 服务虚拟目录配置为需要有客户端证书
1. |
在 Web 服务主机上启动 Internet 信息服务。 |
2. |
导航到 SecureMath 虚拟目录。 |
3. |
右键单击 SecureMath,然后单击“属性”。 |
4. |
单击“目录安全性”选项卡。 |
5. |
单击“安全通信”下的“编辑”。 如果无法使用“编辑”,则很可能是由于没有安装 Web 服务器证书。 |
6. |
选择“要求安全通道 (SSL)”复选框。 |
7. |
选择“需要客户端证书”选项。 |
8. |
单击“确定”,然后再单击“确定”。 |
9. |
在“继承覆盖”对话框中,单击“全选”,然后单击“确定”以关闭 SecureMath 属性对话框。 这会将新的安全设置应用于虚拟根目录下的所有子目录。 |
|
返回页首
创建一个自定义帐户以运行服务组件
此过程在 Web 服务客户端计算机上创建一个新的用户帐户,可用来运行调用 Web 服务的服务组件。
• |
创建一个自定义帐户以运行服务组件
1. |
在客户端计算机上创建一个具有强密码的新用户帐户。清除“用户下次登录时须更改密码”复选框,然后选择“密码永不过期”选项。 |
2. |
将该帐户添加到“管理员”组中。 用于加载用户配置文件的帐户必须是本地计算机的管理员。 |
|
返回页首
为自定义帐户请求一个客户端证书
在此过程中,您将使用新的自定义帐户登录到客户端计算机。然后提出证书请求。此过程假定您使用的是 Microsoft 证书服务。如果您没有使用 Microsoft 证书服务来创建新的证书,请在使用该自定义帐户登录的同时,向您的首选 CA 提出客户端证书请求并安装该证书。
此过程还假定将 Microsoft 证书服务配置为针对证书请求自动颁发证书。还可以将它配置为将申请置为挂起状态(它要求管理员专门颁发证书)。
• |
检查 Microsoft 证书服务设置
1. |
在 Microsoft 证书服务计算机上,在“管理工具”程序组中单击“证书颁发机构”。 |
2. |
展开“证书颁发机构(本地)”,右键单击该证书颁发机构,然后单击“属性”。 |
3. |
单击“策略模块”选项卡,然后单击“配置”。 |
4. |
检查默认操作。 |
|
以下过程假定选定了“始终颁发证书”。
• |
为自定义帐户请求一个客户端证书
1. |
注销客户端计算机并使用自定义帐户重新登录。 这将强制为自定义帐户创建一个用户配置文件。 |
2. |
浏览到该 CA 以请求客户端证书。例如,如果 CA 位于 CAServer 计算机上,请浏览到以下位置。 http://caserver/certsrv
|
3. |
单击“申请一个证书”,然后单击“下一步”。 |
4. |
确保选中了“用户证书”,然后单击“下一步”。 |
5. |
单击“提交”。 此时,将生成一个请求并将它发送到 CA 以进行处理。 |
6. |
在颁发了证书而且您收到了来自 CA 服务器的响应后,单击“安装此证书”。 |
7. |
确保将 CA 颁发的证书作为可信根证书安装到本地计算机上。 要确认这一情况,可执行以下步骤:
1. |
单击任务栏上的“开始”按钮,然后单击“运行”。 |
2. |
键入“mmc”,然后单击“确定”。 |
3. |
在“文件”菜单上,单击“添加/删除管理单元”。 |
4. |
单击“添加”。 |
5. |
单击“证书”,然后单击“添加”。 |
6. |
单击“计算机帐户”,然后单击“下一步”。 |
7. |
单击“本地计算机:(运行本控制台的计算机)”,然后单击“完成”。 |
8. |
单击“关闭”,然后单击“确定”。 |
9. |
在 MMC 管理单元的左侧窗格中,展开“证书(本地计算机)”。 |
10. |
展开“受信任的根证书颁发机构”,然后单击“证书”。 |
11. |
确认您的 CA 的证书已列出。 |
如果该 CA 的证书没有列出,请执行以下步骤:
1. |
浏览到 http://caserver/certsrv。 |
2. |
单击“检索 CA 证书或证书吊销列表”,然后单击“下一步”。 |
3. |
单击“安装此 CA 证书路径”。 |
|
|
返回页首
使用浏览器测试客户端证书
在此过程中,您将浏览到 Web 服务以确认服务器证书或客户端证书都没有问题。
• |
使用浏览器测试客户端证书
1. |
使用 Internet Explorer 并导航到 https://server/SecureMath/Math.asmx。 确保您指定了“https”,因为已将站点配置为要求使用 SSL。 |
2. |
此时应出现“客户身份验证”对话框。选择您的客户端证书,然后单击“确定”。 |
3. |
确认在您的浏览器中成功显示 Web 服务测试页。 如果看到如图 2 所示的对话框,您需要将证书颁发机构的证书安装到“受信任的根证书颁发机构”存储中(正如上一过程中所述)。 图 2 “安全警报”对话框 |
|
返回页首
将客户端证书导出到一个文件中
此过程将客户端证书导出到文件中。随后,当服务组件需要将该证书传递到 Web 服务时,它就会检索该证书。
• |
将客户端证书导出到文件中
1. |
在 Internet Explorer 中,单击“工具”菜单上的“Internet 选项”。 |
2. |
单击“内容”选项卡。 |
3. |
单击“证书”。 |
4. |
单击该客户端证书,然后单击“导出”。 |
5. |
单击“下一步”,跳过证书导出向导的“欢迎”对话框。 |
6. |
确认选中了“不,不要导出私钥”,然后单击“下一步”。 |
7. |
确保选中了“DER 编码二进制 X.509 (.CER)”,然后单击“下一步”。 您必须使用此格式,因为 .NET Framework 不支持 Base-64 或 PKCS #7 格式。 |
8. |
输入一个导出文件名称。请记下 .cer 导出文件的位置,因为在后面的过程中还会需要此位置。 |
9. |
单击“下一步”,然后单击“完成”以导出证书。 |
10. |
关闭 Internet Explorer。 |
11. |
注销计算机并使用您常用的开发帐户重新登录。 |
|
返回页首
开发用于调用该 Web 服务的服务组件
此过程创建一个新的 Visual C# 类库应用程序,并创建用于调用 Web 服务的服务组件。此过程假定您当前在使用客户端计算机。
• |
开发用于调用该 Web 服务的服务组件
1. |
启动 Visual Studio.NET,并创建一个新的名为 WebServiceRequestor 的 Visual C# 类库项目。 |
2. |
添加对 SecureMath Web 服务的 Web 引用。 重要说明:在添加 Web 引用之前,必须暂时将 Web 服务的虚拟目录重新配置为不需要客户端证书(但仍要求使用 SSL)。在成功添加 Web 引用后,将虚拟目录配置改回到需要客户端证书。 实际上,如果站点要求客户端证书,则服务的发布者将 WSDL 作为单独的脱机文件(服务的使用者可用它来创建代理)提供。 在“添加 Web 引用”对话框中,确保在指定 Web 服务位置时指定“https”。如果不这样做,就会出现错误,因为已将 Web 服务虚拟目录配置为要求使用 SSL。 |
3. |
添加一个对 System.EnterpriseServices 程序集的引用。 |
4. |
将 class1.cs 重命名为 ProfileManager.cs。 |
5. |
将以下类定义添加到 ProfileManager.cs 中(替换主干 class1 类)。ProfileManager 类使用 P/Invoke 调用 LoadUserProfile 和 UnloadUserProfile Win32 API。 internal class ProfileManager
{
[DllImport("Userenv.dll", SetLastError=true,
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
internal static extern bool LoadUserProfile(IntPtr hToken,
ref PROFILEINFO lp
ProfileInfo);
[DllImport("Userenv.dll", SetLastError=true,
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
internal static extern bool UnloadUserProfile(IntPtr hToken,
IntPtr hProfile);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct PROFILEINFO
{
public int dwSize;
public int dwFlags;
public String lpUserName;
public String lpProfilePath;
public String lpDefaultPath;
public String lpServerName;
public String lpPolicyPath;
public IntPtr hProfile;
}
}
|
6. |
将名为 MathServiceComponent.cs 的第二个类文件添加到项目中。 |
7. |
将以下 using 语句添加到 MathServiceComponent.cs 中现有 using 语句的下面。 using System.Net;
using System.Web.Services;
using System.Security.Principal;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using WebServiceRequestor.WebReference1;
|
8. |
添加以下类定义(它提供公共 CallMathWebService 方法)。在后面的过程中,您将从客户端 ASP.NET Web 应用程序中调用此方法。 注意:在以下的代码中,请使用您在第 3 章创建自定义帐户以运行服务组件中创建的自定义帐户来替换加载用户配置文件时所使用的帐户名。 // 此类调用需要证书的 Web 服务。
public class MathServiceComponent : ServicedComponent
{
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_
LEVEL,
ref IntPtr DuplicateToken
Handle);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private extern static bool CloseHandle(IntPtr handle);
// 调用需要客户端证书的 Web 服务
// certFilepath 指向要使用的 .cer 文件
// url 是 Web 服务 url
// operand1 和 operand2 是传递给 Web 服务的参数
public long CallMathWebService(String certFilepath,
String url, int operand1, int operand2)
{
bool retVal = false;
// 需要复制令牌。LoadUserProfile 需要一个带有
// TOKEN_IMPERSONATE 和 TOKEN_DUPLICATE 的令牌。
const int SecurityImpersonation = 2;
IntPtr dupeTokenHandle = DupeToken(WindowsIdentity.GetCurrent().Token,
SecurityImpersonation);
if(IntPtr.Zero == dupeTokenHandle)
{
throw new Exception("Unable to duplicate token.");
}
// 加载配置文件。
ProfileManager.PROFILEINFO profile = new ProfileManager.PROFILEINFO();
profile.dwSize = 32;
//应做事项:使用步骤 3 中创建的自定义帐户名替换。
profile.lpUserName = @"machinename/customaccountname";
retVal = ProfileManager.LoadUserProfile(dupeTokenHandle, ref profile);
if(false == retVal)
{
throw new Exception("加载用户配置文件时出错。 " +
Marshal.GetLastWin32Error());
}
// 实例化 Web 服务代理
math mathservice = new math();
mathservice.Url = url;
String certPath = certFilepath;
mathservice.ClientCertificates.Add(
X509Certificate.CreateFromCertFile
(certPath));
long lngResult = 0;
try
{
lngResult = mathservice.Add(operand1, operand2);
}
catch(Exception ex)
{
if(ex is WebException)
{
WebException we = ex as WebException;
WebResponse webResponse = we.Response;
throw new Exception("调用方法时发生异常。 " + ex.Message);
}
}
ProfileManager.UnloadUserProfile(WindowsIdentity.GetCurrent().Token,
profile.hProfile);
CloseHandle(dupeTokenHandle);
return lngResult;
}
private IntPtr DupeToken(IntPtr token, int Level)
{
IntPtr dupeTokenHandle = new IntPtr(0);
bool retVal = DuplicateToken(token, Level, ref dupeTokenHandle);
if (false == retVal)
{
return IntPtr.Zero;
}
return dupeTokenHandle;
}
} // end class
|
9. |
在“生成”菜单上,单击“生成解决方案”。 |
|
返回页首
配置和安装服务组件
此过程将配置服务组件、生成强名称、在全局程序集高速缓存中安装它,并将它在 COM+ 中注册。
1. |
打开 assemblyinfo.cs 并在现有 using 语句之下添加下面的 using 语句。 using System.EnterpriseServices;
|
2. |
将以下程序集级别属性添加到 assemblyinfo.cs 中,以便将服务组件配置为在 COM+ 服务器应用程序中运行。 [assembly: ApplicationActivation(ActivationOption.Server)]
|
3. |
打开一个命令提示窗口并转到当前的项目目录中。 |
4. |
使用 sn.exe 实用程序,生成一个包含公钥-私钥对的密钥文件。 sn.exe -k WebServiceRequestor.snk
|
5. |
返回到 Visual Studio .NET。 |
6. |
在 assemblyinfo.cs 中找到 [AssemblyKeyFile] 属性并对它进行修改,以便按如下方式引用项目目录中的密钥文件。 [assembly: AssemblyKeyFile(@"../../WebServiceRequestor.snk")]
|
7. |
在“生成”菜单上,单击“生成解决方案”。 |
8. |
返回到命令提示窗口并运行以下命令以便将程序集添加到全局程序集高速缓存中。 gacutil.exe /i bin/debug/webservicerequestor.dll
|
9. |
运行以下命令以便在 COM+ 中为程序集注册。 regsvcs bin/debug/webservicerequestor.dll
|
10. |
启动“组件服务”(位于“管理工具”程序组下面)。 |
11. |
展开“组件服务”、“计算机”和“我的电脑”等节点。 |
12. |
展开 COM+ 应用程序文件夹。 |
13. |
右键单击 WebServiceRequestor,然后单击“属性”。 |
14. |
单击“标识”选项卡。 |
15. |
选择“此用户:”选项,并输入与您先前创建的那个自定义帐户对应的帐户详细信息。 这将 COM+ 应用程序配置为使用自定义帐户运行。 |
16. |
单击“确定”以关闭“属性”对话框。 |
17. |
关闭“组件服务”。 |
返回页首
开发一个 Web 应用程序以调用该服务组件
此过程创建一个简单的 ASP.NET Web 应用程序,您将把它作为客户端应用程序来使用以调用 Web 服务(通过服务组件)。
• |
开发一个 Web 应用程序以调用该服务组件
1. |
在 Web 服务客户端计算机上,创建一个新的名为 SecureMathClient 的 Visual C# ASP.NET Web 应用程序。 |
2. |
添加对 System.EnterpriseServices 的引用。 |
3. |
添加对 WebServiceRequestor 服务组件的引用。 浏览到位于 WebServiceRequestor 项目目录下面的 bin/debug 文件夹中的 WebServiceRequestor.dll。 |
4. |
打开 WebForm1.aspx.cs 并在现有 using 语句之下添加下面的 using 语句。 using WebServiceRequestor; |
5. |
在“设计器”模式下查看 WebForm1.aspx,并使用以下 ID 创建如图 2 所示的窗体:
• |
operand1 |
• |
operand2 |
• |
result |
• |
add 图 3 Web 窗体控件排列 |
|
6. |
双击“Add”以创建一个按钮单击事件处理程序。 |
7. |
将下面的代码添加到事件处理程序。 注意:将 certPath 字符串设置为在过程 6“将客户端证书导出到一个文件中”中导出的证书文件的位置。 将 url 字符串设置为您的 Web 服务的 HTTPS URL。 private void add_Click(object sender, System.EventArgs e)
{
// 应做事项:使用您的证书的有效路径替换
字符串 certPath = @"C:/CustomAccountCert.cer";
// 应做事项:使用您的 Web 服务的有效 URL 替换
字符串 url = "https://wsserver/securemath/math.asmx";
MathServiceComponent mathComp = new MathServiceComponent();
long addResult = mathComp.CallMathWebService( certPath,
url,
Int32.Parse(operand1.Text),
Int32.Parse(operand2.Text));
result.Text = addResult.ToString();
}
|
8. |
在“生成”菜单上,单击“生成解决方案”。 |
9. |
运行该应用程序。输入两个要相加的数,然后单击“Add”。 Web 应用程序将调用服务组件,该服务组件将调用使用 SSL 并传递客户端证书的 Web 服务。 |
|
返回页首
其他资源
有关详细信息,请参见本指南的如何在 Web 服务器上设置 SSL。