繁体   English   中英

如何从C#中的Active Directory获取自定义字段?

[英]How can I get a custom field from Active Directory in C#?

我已经阅读了大量类似的StackOverflow问题但似乎没有解决我看到的问题。 如果我使用userprincipalname查询用户,我会返回一个包含34个属性的搜索结果。 没有返回任何自定义属性。 如果我使用像employeeNumber这样的自定义属性再次查询,我会得到71个属性的结果。 包括所有自定义属性。

我的问题是我在运行时没有employeeNumber ,只有userprincipalname 我需要一直恢复所有自定义属性。 希望这是有道理的。 这是我的练习代码:

string sid = "";
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
    UserPrincipal user = UserPrincipal.Current;
    //sid = user.SamAccountName;
    sid = user.UserPrincipalName;
    //sid = user.Sid.ToString();

    DirectoryEntry entry = user.GetUnderlyingObject() as DirectoryEntry;
    if (entry.Properties.Contains("employeeNumber"))
    {
        //this doesn't work
    }
}

DirectoryEntry ldapConnection = new DirectoryEntry("companyname.com");
ldapConnection.Path = "LDAP://DC=companyname,DC=com";
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;

DirectorySearcher search = new DirectorySearcher(ldapConnection);
search.Filter = string.Format("(&(ObjectClass=user)(userprincipalname={0}))", sid); // <-- this doesn't get custom properties
//search.Filter = string.Format("(employeeNumber={0})", "11663"); <-- this works

var result = search.FindOne(); // FindOne();
if (result.Properties.Contains("employeeNumber"))
{
    //this never happens either :(
}

以上永远不会返回employeeNumber字段,但如果我取消注释第二个search.Filter行并按employeeNumber手动搜索,我会找到一个结果,它包含我需要的所有字段。

编辑:我发现了一个很好的MSDN文章下面介绍如何扩展UserPrincipal对象来获取自定义属性。 唯一的问题是,每次访问它时它都会给我一个空字符串,即使我已经验证了属性是在AD中设置的! 任何帮助表示赞赏。

编辑2:这是自定义主要扩展的代码:

[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("Person")]
public class UserPrincipalExtension : UserPrincipal
{
    public UserPrincipalExtension(PrincipalContext context)
        : base(context)
    {
    }

    public UserPrincipalExtension(PrincipalContext context, string samAccountName, string password, bool enabled)
        : base(context, samAccountName, password, enabled)
    {
    }

    public static new UserPrincipalExtension FindByIdentity(PrincipalContext context, IdentityType type, string identityValue)
    {
        return (UserPrincipalExtension)FindByIdentityWithType(context, typeof(UserPrincipalExtension), type, identityValue);
    }

    PersonSearchFilter searchFilter;
    new public PersonSearchFilter AdvancedSearchFilter
    {
        get
        {
            if (searchFilter == null)
                searchFilter = new PersonSearchFilter(this);

            return searchFilter;
        }
    }

    [DirectoryProperty("employeeNumber")]
    public string EmployeeNumber
    {
        get
        {
            if (ExtensionGet("employeeNumber").Length != 1)
                return string.Empty;

            return (string)ExtensionGet("employeeNumber")[0];
        }
        set
        {
            ExtensionSet("employeeNumber", value);
        }
    }
}

和自定义搜索过滤器:

public class PersonSearchFilter : AdvancedFilters
{
    public PersonSearchFilter(Principal p)
        : base(p)
    {
    }

    public void SAMAccountName(string value, MatchType type)
    {
        this.AdvancedFilterSet("sAMAccountName", value, typeof(string), type);
    }
}

用法:

UserPrincipalExtension filter = new UserPrincipalExtension(context);
filter.AdvancedSearchFilter.SAMAccountName(UserPrincipal.Current.SamAccountName, MatchType.Equals);
PrincipalSearcher search = new PrincipalSearcher(filter);

foreach (var result in search.FindAll())
{
    var q = (UserPrincipalExtension)result;
    var m = q.EmployeeNumber;
}

var m始终为空字符串,即使所有AD条目都有employeeNumber。

编辑:从活动目录: 活动目录

我更关心如何修复你的第二种方法,所以我先回答一下。 在搜索要显示的属性时,需要在DirectorySearcher.PropertiesToLoad指定该属性。

DirectorySearcher search = new DirectorySearcher(ldapConnection);
search.Filter = string.Format("(&(ObjectClass=user)(userprincipalname={0}))", sid); 
search.PropertiesToLoad.Add("employeeNumber");

var result = search.FindOne(); // FindOne();
if (result.Properties.Contains("employeeNumber"))
{
    //This should now work.
}

它适用于string.Format("(employeeNumber={0})", "11663"); 是因为您自动添加的任何搜索子句都会被放入PropertiesToLoad集合中。


对于您的第一个方法,我认为您需要调用DirectoryEntry.RefreshCache并传入属性以使其显示。

string sid = "";
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
    UserPrincipal user = UserPrincipal.Current;
    //sid = user.SamAccountName;
    sid = user.UserPrincipalName;
    //sid = user.Sid.ToString();

    DirectoryEntry entry = user.GetUnderlyingObject() as DirectoryEntry;

    entry.RefreshCache(new[] {"employeeNumber"});

    if (entry.Properties.Contains("employeeNumber"))
    {

    }
}

但我不能100%确定这是否有效。


对于您的自定义用户主体,我不确定是什么问题。 我在你所做的事情和我所知道的项目中我所看到的唯一区别是你使用[DirectoryObjectClass("Person")]但我有[DirectoryObjectClass("user")] 也许这就是问题所在

[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("user")] //Maybe this will fix it???
public class UserPrincipalExtension : UserPrincipal
{

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM