25

我有一个 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 身份验证。

4

5 回答 5

20

可以使用表单身份验证模拟用户。下面的代码确实有效

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 。如果你不知道怎么做,谷歌如何做到这一点。

于 2012-08-08T21:52:44.557 回答
0

如果您的用户使用 IE,那么您可以打开网站的集成安全性,您的用户将通过静默方式进行身份验证(没有登录对话框,没有登录页面)。然后,您的模仿将起作用。如果您需要针对其他浏览器,那么这可能不起作用(用户可能会看到一个登录对话框)。

您当前的模拟将永远不会起作用,因为您的用户使用域帐户以外的帐户登录。您不能指望该站点冒充未提供其凭据的用户。这将违背基本的安全原则。

于 2009-06-30T22:24:23.473 回答
0

您可能会发现这很有用:

编辑

在更仔细地阅读您的问题时,我不确定这种方法是否适用于您的情况;当您使用表单身份验证和模拟 Active Directory 用户登录时

于 2009-07-01T12:10:29.487 回答
0

我们最近遇到了同样的问题,客户希望他们的用户可以通过 AD 帐户登录,然后必须使用此凭据访问 Analysis Service 以及所有其他数据库。他们希望这样,因为他们实施了审计系统,并且所有访问都必须由当前登录的帐户完成。

我们尝试了 Forms 身份验证和 Win32 LogonUser() API 来模拟部分,它有效,但它也要求我们以纯文本形式输入用户密码。后来,我们决定使用 Windows 身份验证,它为我们节省了大量时间(不再使用 AD 身份验证,手动模拟)。当然,也没有花哨的登录页面。

于 2011-09-17T16:41:52.380 回答
-1

为了以防万一,有点晚了,我发现了一些对我有用的东西,它真的很简单,但当然只是为了测试目的......

只需使用您的用户名设置一个 cookie。

//Login button. You can give whatever input to the form
protected void Login_Click(object sender, EventArgs e)
{
    FormsAuthentication.SetAuthCookie("your_username", createPersistentCookie: true);
    Response.Redirect("~/");
}

接受任何意见...

于 2014-12-16T05:18:36.490 回答