可以使用表单身份验证模拟用户。下面的代码确实有效。
Robert 提到的Visual Studio Magazine 文章是一个极好的资源。文章中的示例代码存在一些问题,因此我在下面包含了一些工作代码。
注意:如果您使用的是 Visual Studio,请确保以“以管理员身份运行”启动它,以避免 UAC 阻止模拟出现问题。
// in your login page (hook up to OnAuthenticate event)
protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e)
{
int token;
// replace "YOURDOMAIN" with your actual domain name
e.Authenticated = LogonUser(LoginUser.UserName,"YOURDOMAIN",LoginUser.Password,8,0,out token);
if (e.Authenticated) {
Session.Add("principal", new WindowsPrincipal(new WindowsIdentity(new IntPtr(token))));
}
}
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword,
int dwLogonType, int dwLogonProvider, out int TokenHandle);
// in global.asax.cs
void Application_PreRequestHandlerExecute(object send, EventArgs e)
{
if (Thread.CurrentPrincipal.Identity.IsAuthenticated == true && HttpContext.Current.Session != null) {
WindowsPrincipal windowsPrincipal = (WindowsPrincipal)Session["principal"];
Session["principal"] = (GenericPrincipal)Thread.CurrentPrincipal;
Thread.CurrentPrincipal = windowsPrincipal;
HttpContext.Current.User = windowsPrincipal;
HttpContext.Current.Items["identity"] = ((WindowsIdentity)windowsPrincipal.Identity).Impersonate();
}
}
// in global.asax.cs
void Application_PostRequestHandlerExecute(object send, EventArgs e)
{
if (HttpContext.Current.Session != null && Session["principal"] as GenericPrincipal != null) {
GenericPrincipal genericPrincipal = (GenericPrincipal)Session["principal"];
Session["principal"] = (WindowsPrincipal)Thread.CurrentPrincipal;
Thread.CurrentPrincipal = genericPrincipal;
HttpContext.Current.User = genericPrincipal;
((WindowsImpersonationContext)HttpContext.Current.Items["identity"]).Undo();
}
}
// test that impersonation is working (add this and an Asp:Label to a test page)
protected void Page_Load(object sender, EventArgs e)
{
try {
// replace YOURSERVER and YOURDB with your actual server and database names
string connstring = "data source=YOURSERVER;initial catalog=YOURDB;integrated security=True";
using (SqlConnection conn = new SqlConnection(connstring)) {
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT SUSER_NAME()", conn);
using (SqlDataReader rdr = cmd.ExecuteReader()) {
rdr.Read();
Label1.Text = "SUSER_NAME() = " + rdr.GetString(0);
}
}
}
catch {
}
}
更新:
你也应该处理Application_EndRequest
,因为调用likeResponse.End()
会绕过Application_PostRequestHandlerExecute
。
另一个问题是 WindowsIdentity 可能会被垃圾收集,因此您应该在每次请求时从登录令牌创建一个新的 WindowsIdentity 和 WindowsPrincipal。
更新2:
我不确定为什么这会被否决,因为它有效。我添加了 pinvoke 签名和一些测试代码。再次,使用“以管理员身份运行”启动 Visual Studio 。如果你不知道怎么做,谷歌如何做到这一点。