该网站需要模拟通过Active Directory登录的用户访问用户特定的文件。
然而,WindowsIdentity.GetCurrent()与HttpContext.Current.User.Identity不同,尽管我的web.config包含:
<authentication mode="Forms"> <forms loginUrl="login.aspx" timeout="480"/> </authentication> <identity impersonate="true" />
我不能使用LoginUser()和WindowsIdentity.Impersonate(),因为我需要模拟作为AD用户获取他们的特定权限,而且我不知道用户的密码,因为Forms负责登录。
是否可能通过login.aspx.cs来获取System.Web.UI.WebControls.Login.Password,然后将LoginUser()标记保存在WindowsIdentity.Impersonate()的会话变量中?或者也许是一个更安全的假冒正确方法的方法?
我很困惑为什么Forms身份验证不能自动< identity impersonate =“true”/>
我已经阅读了这个http://msdn.microsoft.com/en-us/library/ms998351.aspx,但它使用Windows身份验证。
解决方法
罗伯特提到的Visual Studio Magazine article是一个很好的资源。文章中的示例代码有一些问题,所以我在下面包括一些工作代码。
注意:如果您正在使用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,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,因为像Response.End()这样的调用将绕过Application_PostRequestHandlerExecute。
另一个问题是WindowsIdentity可能会收集垃圾,因此您应该在每次请求时从登录标记创建一个新的WindowsIdentity和WindowsPrincipal。
UPDATE2:
我不知道为什么这会被下调,因为它有效。我添加了pinvoke签名和一些测试代码。再次,使用“以管理员身份运行”启动Visual Studio。谷歌怎么做,如果你不知道如何。