【问题标题】:How to get a username in Active Directory from a display name in C#?如何从 C# 中的显示名称获取 Active Directory 中的用户名?
【发布时间】:2012-03-23 19:33:55
【问题描述】:

我希望能够使用该用户的显示名称获取 Active Directory 中用户的用户 ID。显示名称是从数据库中获取的,并已在该用户的会话期间使用以下代码存储以获取显示名称:

using System.DirectoryServices.AccountManagement;

    private string GetDisplayName()
    {
        // set up domain context
        PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

        // find currently logged in user
        UserPrincipal user = UserPrincipal.Current;

        return user.DisplayName;
    }

这一次,我想要一个名为 GetUserIdFromDisplayName() 的方法,它返回 Active Directory 登录名。有什么想法吗?

【问题讨论】:

  • 我还没有验证它,所以我不能 100% 确定,但我认为你想要 SamAccountName 属性。
  • 你认为,这可能吗?我怀疑用户显示名称是唯一的。可能会导致多重结果。
  • 是的。我现在考虑使用 GUID,而不是使用下面的答案。

标签: c# .net active-directory


【解决方案1】:

我相信通过使用 System.DirectoryServices.AccountManagement (S.DS.AM) 命名空间的内置功能,您可以比使用 David 的回答更容易做到这一点。

基本上,您可以定义域上下文并在 AD 中轻松找到用户和/或组:

using System.DirectoryServices.AccountManagement;

private string GetUserIdFromDisplayName(string displayName)
{
    // set up domain context
    using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
    {
        // find user by display name
        UserPrincipal user = UserPrincipal.FindByIdentity(ctx, displayName);

        // 
        if (user != null)
        {
             return user.SamAccountName;
             // or maybe you need user.UserPrincipalName;
        }
        else
        {
             return string.Empty;
        }
    }
}

我认为没有必要访问底层的 DirectoryEntry 对象,真的 - 除非 UserPrincipal 的所有属性都不是您正在寻找的。​​p>

PS:如果按显示名称搜索不起作用(我手头没有 AD 来测试它) - 您也可以随时使用 PrincipalSearcher 来查找您的用户:

using System.DirectoryServices.AccountManagement;

private string GetUserIdFromDisplayName(string displayName)
{
    // set up domain context
    using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
    {
        // define a "query-by-example" principal - here, we search for a UserPrincipal 
        // and with the display name passed in
        UserPrincipal qbeUser = new UserPrincipal(ctx);
        qbeUser.DisplayName = displayName;

        // create your principal searcher passing in the QBE principal    
        PrincipalSearcher srch = new PrincipalSearcher(qbeUser);

        // find match - if exists
        UserPrincipal user = srch.FindOne() as UserPrincipal;

        if (user != null)
        {
             return user.SamAccountName;
             // or maybe you need user.UserPrincipalName;
        }
        else
        {
             return string.Empty;
        }
    }
}

【讨论】:

  • +1,更简单快捷,还能找到 DOMAIN\USERID 条目
  • 我能够使用UserPrincipal.FindByIdentity(ctx, IdentityTypes.SamAccountName, username) 按他们的 DOMAIN\USERNAME 找到用户,所以我假设您想像代码状态一样返回 user.SamAccountName
  • FindByIdentit() 是按用户原则查找的。用户原则本质上与显示名称不同。如果您创建一个显示名称为“ABC”的新用户。稍后您可以将其更改为“A B C”。用户原理不会更新,上面的脚本也找不到这个用户。
【解决方案2】:

UserPrincipal 有一个方法 GetUnderlyingObject() 将返回 DirectoryEntry

从 Principal 获取 DirectoryEntry:

private DirectoryEntry GetDirectoryEntryFromUserPrincipal(Principal user)
{
    return (DirectoryEntry)user.GetUnderlyingObject();
}

从域和帐户名获取 DirectoryEntry:

private DirectoryEntry GetDirectoryEntryFromDomainAndUsername(string domainName, string userName)
{
    // Get the sid from the NT account name
    var sid = (SecurityIdentifier) new NTAccount(domainName, accountName)
                  .Translate(typeof(SecurityIdentifier));

    // Get the directory entry for the LDAP service account
    var serviceEntry = new DirectoryEntry("LDAP://{address}", "serviceUsername", "servicePassword");

    var mySearcher = new DirectorySearcher(serviceEntry)
        {
            Filter = string.Format("(&(ObjectSid={0}))", sid.Value)
        };

    return mySearcher.FindOne().GetDirectoryEntry();
}

拥有DirectoryEntry 后,使用Guid 属性获取条目的Object-Guid

private Guid GetObjectGuidFromDirectoryEntry(DirectoryEntry entry)
{
    // return the Guid this is the Object-Guid (ignore NativeGuid)
    return entry.Guid;
}

针对目录帐户跟踪应用程序中的用户帐户:始终使用 Object-Guid 作为“此值在创建对象时设置且无法更改。”
如果用户更改域或更常见的是更改其名称(婚姻、合法名称更改等),NT 和 SAM 帐户名称可能会更改,并且不应用于跟踪用户。

获取 NT 帐户名(域\用户名):

private string GetNTAccountNameFromDirectoryEntry(DirectoryEntry entry)
{
    PropertyValueCollection propertyValueCollection = entry.Properties["objectsid"];

    SecurityIdentifier sid = new SecurityIdentifier((byte[]) propertyValueCollection[0], 0);

    NTAccount ntAccount = (NTAccount)sid.Translate(typeof (NTAccount));

    return account.ToString();
}

获取 SAM-Account-Name (username@domain):

private string GetSAMAccountFromDirectoryEntry(DirectoryEntry entry)
{
    return entry.Properties["Name"].Value;
}

这里是所有 Active Directory 属性的exhaustive list。从Properties获取值时使用“Ldap-Display-Name”
例如Properties["Ldap-Display-Name"]

Display-Name (FirstName MI LastName) 可能会派上用场。

【讨论】:

  • 谢谢!然后我想您必须通过执行以下操作从 AD 组获取 UserPrincipal 对象:social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/…
  • 那行得通。我看到您在问题中使用了UserPrincipal.Current。如果 Web 应用程序托管在域中,使用“Windows 安全性”,或者是在用户会话中运行的本机应用程序,则此方法有效。如果只能查询AD,那么直接通过SAM-Account-Name过滤获取目录项。
  • 添加了 GetDirectoryEntryFromDomainAndUsername。这可能需要一些调整,因为我不在一个可以针对 AD 服务器测试所有这些的环境中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-14
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多