【问题标题】:Active directory access and IIS Authetication method issueActive Directory 访问和 IIS 身份验证方法问题
【发布时间】:2019-11-25 10:11:31
【问题描述】:

我有一个根据 Active Directory 对用户进行身份验证的 Intranet 应用程序。一般来说,在本地测试(即从我的开发机器使用 VS 2017)或在应用服务器中从 IIS 运行它(“Browse *:80”)时它工作正常,直到我尝试使用本地机器上的 URL 访问它。然后无论我使用什么用户 ID 来获取用户的详细信息,都不会显示任何内容。

此外,某些组中的用户可以访问此应用程序,因此应用程序会检查已登录用户的组成员身份。

这是我在 IIS 中设置它的方式以及我测试过的不同场景:

  • 我将身份验证设置为“Windows 身份验证”,禁用匿名 身份验证并启用 AS.NET 模拟。这工作正常时 使用 localhost 从应用服务器运行,但尝试访问时 从我的本地机器并提供用户的用户 ID 以获取他/她 详细信息,不显示详细信息(无法从 广告)。
  • 如果我启用匿名身份验证并将其设置为“应用程序池标识”(即网络服务),它会显示我的自定义 “访问被拒绝”页面,大概是因为此用户不属于 允许的组。
  • 如果我启用匿名身份验证并选择“特定用户”并提供我的凭据,那么无论从应用服务器还是从我的本地计算机,一切正常,但需要注意的是:无论谁访问该站点,我的名字都会显示为登录用户。

我很困惑广告希望能得到一些提示。

更新 - 添加了获取用户信息的代码

获取用户身份的代码:

WindowsIdentity wiUser = WindowsIdentity.GetCurrent();
string sID = wiUser.Name.ToUpper();

获取用户广告信息的代码:

static string adDomain = "www.xxx.yyy.zzz";
static string adContainer = "DC=www,DC=xxx,DC=yyy,DC=zzz";

public static DataTable getUserADInfoDT(string sSearchStr)
{
    DataTable dtResults = new DataTable();
    dtResults.Columns.Add("ID");
    dtResults.Columns.Add("FirstName");
    ...
    dtResults.Columns.Add("Zip");

    string adDomain = string.Empty;
    string adContainer = string.Empty;

    // create domain context
    PrincipalContext adPrincipalContext = new PrincipalContext(ContextType.Domain, adDomain, adContainer);

    using (adPrincipalContext)
    {
        // define a "query-by-example" principal 
        UserPrincipal qbeUser = new UserPrincipal(adPrincipalContext);
        qbeUser.SamAccountName = sSearchStr.Trim().ToUpper();

        // create principal searcher passing in the QBE principal    
        PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
        PrincipalSearchResult<Principal> psr = srch.FindAll();

        // find all matches
        foreach (var found in psr)
        {
            DataRow dr = dtResults.NewRow();
            UserPrincipal up = (UserPrincipal)found;
            DirectoryEntry de = (DirectoryEntry)up.GetUnderlyingObject();

            dr["ID"] = de.Properties["SAMAccountName"].Value.ToString().ToUpper(); 

            if (de.Properties["givenName"].Value != null) 
                dr["FirstName"] = de.Properties["givenName"].Value.ToString();

            ...

            if (de.Properties["postalCode"].Value != null)
                dr["Zip"] = de.Properties["postalCode"].Value.ToString();

            dtResults.Rows.Add(dr);
            //de.Close();
        }
        return dtResults;
    }
}

【问题讨论】:

  • 让我们忽略您描述的后两个场景,因为这显然不是您想要的。您需要启用 Windows 身份验证。您可以编辑您的问题并添加用于检查用户 ID 的代码吗?我怀疑这是你问题的根源。
  • 这显示了您如何在 AD 中查找用户名。但是您从哪里获得传递给sSearchStr 参数的值?这就是我所说的重要部分。
  • 编辑了以前的编辑并添加了几行如何获取用户的身份。

标签: c# active-directory iis-7.5


【解决方案1】:

WindowsIdentity.GetCurrent() 将获取当前进程正在运行的用户帐户。如果应用程序在 IIS 中运行,那通常是运行应用程序池的用户帐户,而不是登录到您的应用程序的用户。

如果您使用 IIS Express 在本地进行调试,那么 IIS Express 将在您的用户帐户下运行,因此您不会看到任何差异。但是在服务器上你会的。

也就是说,如果您启用了模拟并且工作正常,那么WindowsIdentity.GetCurrent() 应该返回登录的用户 - 因为模拟意味着您的应用现在假装是那个人。所以这可能意味着模拟设置不正确。但也许你甚至不需要它。我个人从未发现需要使用模拟。

要获取登录到您应用的用户,您应该使用HttpRequest.Current.User,如果您的应用是 ASP.NET MVC,则可能只使用HttpContext.User

实际上还有一种更简单的方法可以为用户获取DirectoryEntry 对象,而无需搜索用户名。您可以直接绑定到用户的 SID,这是您已经拥有的信息:

var user = new DirectoryEntry(
    $"LDAP://<SID={((WindowsIdentity) HttpContext.User.Identity).User.Value}>");

如果您的服务器未与您的用户加入同一个域,那么您可能需要包含域名:

var user = new DirectoryEntry(
    $"LDAP://www.xxx.yyy.zzz/<SID={((WindowsIdentity) HttpContext.User.Identity).User.Value}>");

还有一点要记住:DirectoryEntry 保留了所有 Properties 的缓存。当您访问缓存中不存在的属性时,它会发送到 AD 并请求 每个具有值的属性。如果您只需要 3 个属性,那将是通过网络传输的大量无用数据。因此,您可以告诉它在使用它们之前只专门询问这 4 个属性:

user.RefreshCache(new[] {"SAMAccountName", "givenName", "postalCode"});

我在我写的一篇文章中谈到了这一点和其他几点:Active Directory: Better Performance

更新:要验证 IIS 是否实际上对页面强制执行身份验证,您可以在 PowerShell 中执行此操作(将 URL 更新为您需要的内容 - 这至少需要 PowerShell 3):

try { (Invoke-WebRequest "http://example.com/the/page").StatusCode }
    catch { $_.Exception.Response.StatusCode.Value__}

这将输出回复的状态码。您应该看到401,因为这是 IIS 挑战浏览器发送凭据的方式。如果您看到 200,则 Windows 身份验证不适用于该页面。

我在 PowerShell 中执行此操作,因为 Chrome 的开发工具甚至不会向您展示 401 挑战。

【讨论】:

  • 我确实启用了模拟,并且用户在访问该站点时,会在页面顶部看到他们赢得的用户 ID 和名称;所以它必须正常工作。只有当我在其中一个页面中尝试访问 AD 以根据 ID 搜索获取用户信息时,事情才会横向发展。另外,当我尝试“string sID = HttpContext.Current.User.Identity.Name;”时我得到空字符串。
  • 这意味着他们没有经过身份验证。您是否为站点或仅为该页面启用了匿名身份验证?或者,如果您使用的是 MVC,除了该页面之外,您是否在其他任何地方都使用了 [Authorize] 属性?
  • 否,匿名身份验证已禁用,ASP.NET 模拟和 Windows 身份验证已启用,并且我没有使用 MVC。
  • 您的 web.config 中是否有任何 &lt;location&gt; 标记可能会更改该特定页面的身份验证?
  • 我在 web.config 中有几个位置标签,但它们只调整 maxrequestLength 和 executionTimeouts,没有一个与相关页面相关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-08
  • 1970-01-01
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多