你的问题很清楚。在当前的实现中,您只有模拟用户,没有委托。我不想重复斯蒂芬马丁已经写过的信息。我只想添加至少三个解决方案。Stephen Martin 建议的经典委托方式只是一种方式。您可以在这里阅读更多方式:http: //msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_delegation。我看到了解决问题的三种实用方法:
将用户的模拟令牌转换为具有模拟授权级别的令牌或新的主令牌。您可以针对DuplicateToken
or执行此操作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 中编写一个使用您需要的 API 的小型 COM 组件。例如,您可以使用来自http://support.microsoft.com/kb/248187/en的代码。但是你应该在里面做一些其他的事情。所以我现在解释哪个 Win32 API 可以帮助您使用令牌和模拟来完成您需要的一切。
首先是关于模仿的一个小解释。一切都很容易。总有一个主令牌在其下运行进程。可以为任何线程分配另一个令牌(线程令牌)。为此,需要拥有用户令牌hUserToken
并调用 API ImpersonateLoggedOnUser(hUserToken);
。
要返回原始进程令牌(仅适用于当前线程),您可以调用RevertToSelf()
function. 用户的令牌将被 IIS 接收并已为您模拟,因为您如此配置了您的网站。要返回原始进程令牌,您应该RevertToSelf()
在自定义 COM 组件中实现该函数的调用。可能,如果您不需要在 ASP 页面中执行更多操作,就足够了,但我建议您在操作文件之前更加小心,并将当前用户令牌保存在变量中。然后您对文件系统进行所有操作,最后将用户令牌重新分配回当前线程。您可以将模拟令牌分配给与 相关的线程SetThreadToken(NULL,hUserToken);
。要提供(保存)当前线程令牌(在您的情况下为用户令牌),您可以使用OpenThreadToken
API。它必须工作。
更新2:可能在一个 ASP 页面末尾RevertToSelf()
使用函数对您来说已经可以了。对应的 C# 代码可以是这样的:
在 C# 中创建一个名为“类库”的新项目LoginAdmin
。将以下代码粘贴到里面
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