ASP页面在IIS下使用Windows身份验证运行,并启用了模拟.
如果我通过CScript.exe在本地运行以下代码块:
var objNet = new ActiveXObject("WScript.Network"); WScript.Echo(objNet.ComputerName); WScript.Echo(objNet.UserName); WScript.Echo(objNet.UserDomain); var fso = new ActiveXObject("Scripting.FileSystemObject"); var path = "\\\\myserver\\my_share\\some_path"; if (fso.FolderExists(path)) { WScript.Echo("Yes"); } else { WScript.Echo("No"); }
我得到(预期)输出:
MY_COMPUTER dylan.beattie MYDOMAIN Yes
如果我在.ASP页面中运行相同的代码,则将Response.Write替换为WScript.Echo,我得到以下输出:
MY_COMPUTER dylan.beattie MYDOMAIN No
现在 – 我的理解是WScript.Network对象将检索实际运行代码的线程的当前安全凭证.如果这是正确的 – 那么为什么在同一个域上的同一个用户从CScript.exe到ASP获得不同的结果?如果我的ASP代码以dylan.beattie运行,那为什么我看不到网络共享?如果它不像dylan.beattie那样运行,为什么WScript.Network会认为它是?
解决方法
>将用户的模拟令牌转换为具有委派级别模拟或新主要令牌的令牌.您可以对DuplicateToken或DuplicateTokenEx执行此操作.
>使用S4U2Self(参见http://msdn.microsoft.com/en-us/magazine/cc188757.aspx和http://msdn.microsoft.com/en-us/library/ms998355.aspx)从一个简单的.NET语句接收旧令牌的新令牌WindowsIdentity wi = new WindowsIdentity(identity);
>您可以访问一个固定帐户的另一台服务器.它可以是IIS应用程序池帐户上的计算机帐户.它可以是另一个固定定义的帐户,只能用于访问文件系统.
了解运行IIS的服务器上的Windows Server版本以及域中Active Directory中的域功能级别非常重要(如果选择域,则可在“Active Directory域和信任”工具中看到此功能并选择“提升域功能级别”).知道IIS的应用程序池在哪个帐户下运行也很有趣.
第一种和第三种方式将始终有效.第三种方式可能对您的环境和文件系统中的当前权限有害.第二个非常优雅.它允许控制从IIS访问哪些服务器(文件服务器).这种方式有一些限制,需要在Active Directory中完成一些工作.
因为您使用经典ASP,所以必须创建一个小的可编写脚本的软件组件来支持您的实现.
你更喜欢哪种方式?
更新基于注释中的问题:因为您使用经典ASP,您不能直接使用Win32 API,但您可以在VB6或.NET中编写一个小型COM组件,它使用您需要的API.作为一个例子,你可以使用http://support.microsoft.com/kb/248187/en中的代码.但是你应该在里面做一些其他的事情.所以我现在解释一下哪个Win32 API可以帮助你做所有你需要的令牌和模仿.
首先是一个关于冒充的小解释.一切都很容易.始终有一个主令牌运行该进程.对于任何线程,可以分配另一个令牌(线程令牌).要做到这一点,需要有一个用户hUserToken的标记并调用API ImpersonateLoggedOnUser(hUserToken);.
要返回原始进程令牌(仅适用于当前线程),可以调用RevertToSelf()函数. IIS将收到用户令牌并已为您模拟,因为您已配置了您的网站.要返回原始进程令牌,您应该在自定义COM组件中实现函数RevertToSelf()的调用.也许,如果你不需要在ASP页面中做更多的事情,那就足够了,但我建议你在使用文件操作之前要更加小心并将当前用户令牌保存在变量中.然后使用文件系统进行所有操作,最后将用户令牌重新分配回当前线程.您可以根据SetThreadToken(NULL,hUserToken);为模拟分配模拟令牌.要提供(保存)当前线程令牌(在您的情况下为用户令牌),您可以使用OpenThreadToken API.它必须工作.
更新2:在一个ASP页面的末尾使用RevertToSelf()函数可能已经可以了.相应的C#代码可以是这样的:
使用名称LoginAdmin在“类库”类型的C#中创建一个新项目.将以下代码粘贴到其中
using System; using System.Runtime.InteropServices; namespace LoginAdmin { [InterfaceTypeAttribute (ComInterfaceType.InterfaceIsDual)] public interface IUserImpersonate { [DispId(1)] bool RevertToSelf (); } internal static class NativeMethods { [DllImport ("advapi32.dll",SetLastError = true)] internal static extern bool RevertToSelf (); } [ClassInterface (ClassInterfaceType.AutoDual)] public class UserImpersonate : IUserImpersonate { public UserImpersonate () { } public bool RevertToSelf () { return NativeMethods.RevertToSelf(); } } }
在“构建”部分“注册COM互操作”中签入项目属性.在项目的“签名”部分检查签署程序集并在“选择强名称密钥文件”中选择< New ...>,然后键入任何文件名和密码(或选中“保护我的密钥…” ).最后,您应该在项目的Properties部分中的AssemblyInfo.cs中修改一行:
[assembly: ComVisible (true)]
编译此项目后,您将获得两个文件:LoginAdmin.dll和LoginAdmin.tlb. DLL已在当前计算机上注册.要在另一台计算机上注册,请使用RegAsm.exe.
要在ASP页面上测试此COM DLL,您可以执行以下操作
<%@ Language="javascript" %> <html><body> <% var objNet = Server.CreateObject("WScript.Network"); Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>"); Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>"); var objLoginAdmin = Server.CreateObject("LoginAdmin.UserImpersonate"); var isOK = objLoginAdmin.RevertToSelf(); if (isOK) Response.Write("RevertToSelf return true<br/>"); else Response.Write("RevertToSelf return false<br/>"); Response.Write("One more time after RevertToSelf()<br/>"); Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>"); Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>"); var fso = Server.CreateObject("Scripting.FileSystemObject"); var path = "\\\\mk01\\C\\Oleg"; if (fso.FolderExists(path)) { Response.Write("Yes"); } else { Response.Write("No"); }%> </body></html>
如果用于运行IIS应用程序池的帐户可以访问相应的网络共享,则输出将如下所示
Current user: Oleg Current user's domain: WORKGROUP RevertToSelf return true One more time after RevertToSelf() Current user: DefaultAppPool Current user's domain: WORKGROUP Yes