C# 在 Active Directory 中使用登录名查找用户
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/161398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Finding a User in Active Directory with the Login Name
提问by Michael Stum
I'm possibly just stupid, but I'm trying to find a user in Active Directory from C#, using the Login name ("domain\user").
我可能只是愚蠢,但我正在尝试使用登录名(“域\用户”)从 C# 中查找 Active Directory 中的用户。
My "Skeleton" AD Search Functionality looks like this usually:
我的“骨架”广告搜索功能通常如下所示:
de = new DirectoryEntry(string.Format("LDAP://{0}", ADSearchBase), null, null, AuthenticationTypes.Secure);
ds = new DirectorySearcher(de);
ds.SearchScope = SearchScope.Subtree;
ds.PropertiesToLoad.Add("directReports");
ds.PageSize = 10;
ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2);
SearchResult sr = ds.FindOne();
Now, that works if I have the full DN of the user (ADSearchBase usually points to the "Our Users" OU in Active Directory), but I simply have no idea how to look for a user based on the "domain\user" syntax.
现在,如果我拥有用户的完整 DN(ADSearchBase 通常指向 Active Directory 中的“我们的用户”OU),这将起作用,但我根本不知道如何根据“域\用户”语法查找用户.
Any Pointers?
任何指针?
采纳答案by Joe
You need to set a filter (DirectorySearcher.Filter) something like:
您需要设置一个过滤器(DirectorySearcher.Filter),例如:
"(&(objectCategory=person)(objectClass=user)(sAMAccountName={0}))"
"(&(objectCategory=person)(objectClass=user)(sAMAccountName={0}))"
Note that you only specify the username (without the domain) for the property sAMAccountName. To search for domain\user, first locate the naming context for the required domain, then search there for sAMAccountName.
请注意,您仅为属性 sAMAccountName 指定用户名(不带域)。要搜索域\用户,首先找到所需域的命名上下文,然后在那里搜索 sAMAccountName。
By the way, when building LDAP query strings using String.Format, you should generally be careful to escape any special characters. It probably isn't necessary for an account name, but could be if you're searching by other properties such as the user's first (givenName property) or last (sn property) name. I have a utility method EscapeFilterLiteral to do this: you build your string like this:
顺便说一下,在使用 String.Format 构建 LDAP 查询字符串时,您通常应该小心转义任何特殊字符。帐户名称可能不是必需的,但如果您正在搜索其他属性,例如用户的名字(givenName 属性)或姓氏(sn 属性)名称,则可能是必需的。我有一个实用方法 EscapeFilterLiteral 来执行此操作:您可以像这样构建字符串:
String.Format("(&(objectCategory=person)(objectClass=user)(sn={0}))",
EscapeFilterLiteral(lastName, false));
where EscapeFilterLiteral is implemented as follows:
其中 EscapeFilterLiteral 实现如下:
public static string EscapeFilterLiteral(string literal, bool escapeWildcards)
{
if (literal == null) throw new ArgumentNullException("literal");
literal = literal.Replace("\", "\5c");
literal = literal.Replace("(", "\28");
literal = literal.Replace(")", "\29");
literal = literal.Replace(""(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370)(sAMAccountName=John))"
", "\00");
literal = literal.Replace("/", "\2f");
if (escapeWildcards) literal = literal.Replace("*", "\2a");
return literal;
}
This implementation allows you treat the * character as part of the literal (escapeWildcard = true) or as a wildcard character (escapeWildcard = false).
此实现允许您将 * 字符视为文字的一部分 (escapeWildcard = true) 或作为通配符 (escapeWildcard = false)。
UPDATE: This is nothing to do with your question, but the example you posted does not call Dispose on the disposable objects it uses. Like all disposable objects these objects (DirectoryEntry, DirectorySearcher, SearchResultCollection) should always be disposed, normally with the using statement. See this postfor more info.
更新:这与您的问题无关,但是您发布的示例并未在它使用的一次性对象上调用 Dispose。像所有一次性对象一样,这些对象(DirectoryEntry、DirectorySearcher、SearchResultCollection)应该总是被处理,通常使用 using 语句。有关更多信息,请参阅此帖子。
回答by Michael Stum
Thanks. I figured that i can get the Domain (at least in my AD) through specifying "LDAP://{0}.somedomain.com/DC={0},DC=somedomain,DC=com", replacing {0} with the domain, which works in our my environment at least.
谢谢。我想我可以通过指定“LDAP://{0}.somedomain.com/DC={0},DC=somedomain,DC=com”来获取域(至少在我的 AD 中),将 {0} 替换为域,至少在我的环境中有效。
One question though: sAMAccountName seems depreciated: The logon name used to support clients and servers running older versions of the operating system, such as Windows NT 4.0, Windows 95, Windows 98, and LAN Manager. This attribute must be less than 20 characters to support older clients.
但有一个问题:sAMAccountName 似乎已贬值:用于支持运行旧版本操作系统(如 Windows NT 4.0、Windows 95、Windows 98 和 LAN Manager)的客户端和服务器的登录名。此属性必须少于 20 个字符以支持旧客户端。
Is this still the best approach to it? Or is there a more "modern" field to query? (Windows 2003 Active Directory, Windows XP or 2003 Clients, .net 3.0)
这仍然是最好的方法吗?或者是否有更“现代”的字段可以查询?(Windows 2003 Active Directory、Windows XP 或 2003 客户端、.net 3.0)
Edit:Thanks again. Our structure is a bit complicated: we have a big "domain.com" forest, with several domains for regional offices. Essentially: The Login is "something\username", the full domain us something.domain.com and the mail is [email protected] (without the something), but the principal name is [email protected]. I will manually "translate" something\username to [email protected], as this seems to be the most robust way. Especially since I want to keep the Auto-Discovery feature in.
编辑:再次感谢。我们的结构有点复杂:我们有一个很大的“domain.com”林,其中有几个用于区域办事处的域。本质上:登录名是“something\username”,完整的域是something.domain.com,邮件是[email protected](没有something),但主体名称是[email protected]。我将手动“翻译”something\username 到 [email protected],因为这似乎是最可靠的方式。特别是因为我想保留自动发现功能。
回答by kombsh
Logon Name(Pre-Windows 2000)
登录名(Windows 2000 之前的版本)
"(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370)(userPrincipalName=John))"
Logon Name(Windows 2000 and above)
登录名(Windows 2000 及以上)
##代码##