【发布时间】:2015-01-23 11:43:33
【问题描述】:
我在使用代码 (C#) 模拟 ASP.NET 和使用 SQL Server Express 时遇到问题:
我能够成功模拟并连接到 SQL Server,但是执行 SELECT CURRENT_USER 返回 guest 而不是 TestUser_001。
注意:我尝试使用LOGON32_LOGON_NETWORK_CLEARTEXT 进行模拟,然后在调用LogonUser 时使用LOGON32_LOGON_INTERACTIVE - 结果保持不变。我正在执行此模拟代码的帐户设置了Act as part of the operating system。在 IIS Express(Visual Studio 2013 中的 F5)下测试。我从未以TestUser_001 的身份交互登录并连接到SQL Server Express 实例——Security\Logins 下没有MY_DOMAIN\TestUser_001——希望在使用代码时自动发生这种情况。
using (var impersonation = new ImpersonationHelper("TestUser_001", "MY_DOMAIN", "pass"))
{
using (var conn = new SqlConnection(@"Data Source=MY_DOMAIN\SQLEXPRESS;Integrated Security=True;"))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT CURRENT_USER";
var result = cmd.ExecuteScalar();
}
}
}
这是基本的ImpersonationHelper 实现:
public class ImpersonationHelper : IDisposable
{
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
public const int LOGON32_PROVIDER_DEFAULT = 0;
[DllImport("advapi32.dll")]
public static extern int LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken
);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken
);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
private readonly WindowsImpersonationContext impersonationContext_;
public ImpersonationHelper(string username, string domain, string password)
{
var token = IntPtr.Zero;
var token_duplicate = IntPtr.Zero;
if (RevertToSelf())
{
if (LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if (DuplicateToken(token, 2, ref token_duplicate) != 0)
{
var temp_windows_identity = new WindowsIdentity(token_duplicate);
impersonationContext_ = temp_windows_identity.Impersonate();
if (impersonationContext_ != null)
{
CloseHandle(token);
CloseHandle(token_duplicate);
return;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(token);
if (token_duplicate != IntPtr.Zero)
CloseHandle(token_duplicate);
throw new Exception(string.Format("Unable to impersonate as {0}\\{1}.", username, domain));
}
public void Dispose()
{
impersonationContext_.Undo();
}
}
【问题讨论】:
-
什么是 ImpersonationHelper?构造函数是否已经执行了模拟,还是需要先调用某个方法?
-
ImpersonationHelper已经进行了模拟。WindowsIdentity.GetCurrent().Name在ImpersonationHelper之后调用,在连接到 SQL Express 之前返回My_DOMAIN\TestUser_001。 -
SELECT SUSER_SNAME();返回什么? -
SELECT SUSER_SNAME();确实返回MY_DOMAIN\TestUser_001,但用户登录名未列在 Security\Logins 下。
标签: c# asp.net sql-server sql-server-express impersonation