簡體   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