Asp.net

使用表單身份驗證進行模擬

  • June 30, 2009

我有一個 ASP.NET 站點,它必須使用表單身份驗證而不是 Windows 身份驗證來訪問ActiveDirectoryMembershipProvider. 該站點必須使用表單,因為它們需要設計的輸入表單,而不是 Windows 身份驗證使用的瀏覽器身份驗證彈出視窗。

該站點需要模擬通過 Active Directory 登錄的使用者來訪問使用者特定的文件。

但是,WindowsIdentity.GetCurrent()儘管HttpContext.Current.User.Identity我的 web.config 包含:

<authentication mode="Forms">
   <forms loginUrl="login.aspx" timeout="480"/>
</authentication>
<identity impersonate="true" />

我不能使用LoginUser()and ,WindowsIdentity.Impersonate()因為我需要冒充 AD 使用者來獲得他們的特定權限,而且我不知道使用者的密碼,因為 Forms 負責登錄。

是否有可能從 login.aspx.cs 獲取System.Web.UI.WebControls.Login.Password,然後將LoginUser()令牌保存在會話變數中以WindowsIdentity.Impersonate()備後用?或者也許是一種更安全的以正確方式模擬的方法?

我很困惑為什麼表單身份驗證不能自動<identity impersonate="true" />

我讀過這個<http://msdn.microsoft.com/en-us/library/ms998351.aspx>但它使用 Windows 身份驗證。

可以使用表單身份驗證模擬使用者。下面的程式碼確實有效

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 。如果你不知道怎麼做,Google如何做到這一點。

引用自:https://stackoverflow.com/questions/1066275