繁体   English   中英

尝试访问 Active Directory 中的属性以添加到数据库

[英]Trying to access Properties in Active Directory to add to a Database

根据输入的 ID 从 AD 中提取用户信息。 我得到的错误是:

无法将类型“字符串”隐式转换为类型“System.DirectoryServices.DirectoryEntry”

发生在Save方法中:

DirectoryEntry de = new DirectoryEntry();
de = QueryAD(objSearchRolesViewModel.NID);

打开连接:

private DirectoryEntry GetDirectoryObject()
{
    DirectoryEntry oDE;
    oDE = new DirectoryEntry("LDAP://myConnection");
    return oDE;
}

查询广告:

public string QueryAD(string userNID)
{
    DirectorySearcher ds = new DirectorySearcher
        {
            SearchRoot = new DirectoryEntry(""),
            //start searching from local domain
            Filter = userNID
        };

    ds.PropertiesToLoad.Add("givenname");
    ds.PropertiesToLoad.Add("sn");
    ds.PropertiesToLoad.Add("mail");

    // start searching
    SearchResultCollection searchCollection = ds.FindAll();

    try
    {
        foreach (SearchResult result in searchCollection)
        {
            if (result.Properties.PropertyNames != null)
                foreach (string propKey in result.Properties.PropertyNames)
                {
                    // Display each of the values for the property identified by the property name.
                    foreach (object prop in result.Properties[propKey])
                    {
                        if ((propKey == "userPrincipalName"))
                        {
                            return prop.ToString();
                        }
                    }
                }

            return "Unknown User";
        }
        catch (Exception ex)
        {
            return "Unknown User";
        }
}

保存新用户:

public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
    DirectoryEntry de = new DirectoryEntry();
    de = QueryAD(objSearchRolesViewModel.NID);

    USERACCOUNT objUserAccount = new USERACCOUNT
        {
            HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
            DOMAIN = "Aeth",
            NTUSERID = objSearchRolesViewModel.User_Id,
            ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
            FIRSTNAME = GIVENNAME GOES HERE,
            LASTNAME = SURNAME GOES HERE,
            EMAIL = MAIL GOES HERE,
            ACTIVE = true/*Convert.ToBoolean(objSearchRolesViewModel.ActiveStatus)*/,
            DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
            CREATEID = userID,
            CREATEDATE = DateTime.Now,
            UPDATEID = userID,
            UPDATEDATE = DateTime.Now
        };

    _context.USERACCOUNTs.Add(objUserAccount);
    _context.SaveChanges();
}

我需要能够从 Active Directory 访问属性并将它们添加到添加新用户时发送到数据库的内容中。

在您的代码中, QueryAD(objSearchRolesViewModel.NID); 返回一个字符串,但您将其分配给 DirectoryEntity。 这行不通。

public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
        {
           DirectoryEntry de = new DirectoryEntry();
                de = QueryAD(objSearchRolesViewModel.NID); // <--- This is the issue.
...

从 QueryAD 函数查找 DirectoryEntry 并返回该对象以使您的调用工作。

public string QueryAD(string userNID) // You will need to return DirectoryEntry to make your code work.
        {
            DirectorySearcher ds = new DirectorySearcher

编辑:

我发现将 UserPrincipal 与 PrincipalContext 一起使用要简单得多。 使用您的域名查找 PrincipalContext 并在未使用域帐户运行时提供凭据。 然后,简单地通过 SamAccountName、Name/ID 或 DistinguishedName 查找用户。

您将需要'System.DirectoryServices.AccountManagement' nuget 包以供主体使用。

public static UserPrincipal QueryAD(string UserName)
    {

        PrincipalContext context = new PrincipalContext(ContextType.Domain, "Aeth", "user", "password");

        // Without creds if the account running the code is already a domain account
        //PrincipalContext context = new PrincipalContext(ContextType.Domain, "Aeth"); 

        // You can search the account by SamAccountName, DistinguishedName, UserPrincipalName or SID
        return UserPrincipal.FindByIdentity(context, IdentityType.Name, UserName);


    }
    public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
    {
        UserPrincipal user = QueryAD(objSearchRolesViewModel.User_Id);

        USERACCOUNT objUserAccount = new USERACCOUNT
        {

            HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
            DOMAIN = "Aeth",
            NTUSERID = objSearchRolesViewModel.User_Id,
            ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
            FIRSTNAME = user.GivenName, // Get FirstName
            LASTNAME = user.Surname,    // Get LastName
            EMAIL = user.EmailAddress,  // Get Email Address
            ACTIVE =  user.Enabled,     // Get User Status
            DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
            CREATEID = userID,
            CREATEDATE = DateTime.Now,
            UPDATEID = userID,
            UPDATEDATE = DateTime.Now
        };
        _context.USERACCOUNTs.Add(objUserAccount);
        _context.SaveChanges();

    }

以下是使用 DirectoryEntry 方法的代码。 如果您使用无权访问 AD 的帐户运行此代码,请确保添加凭据。

搜索广告的方法

 public DirectoryEntry QueryAD(string UserName)
        {
            try
            {
                DirectorySearcher ds = new DirectorySearcher
                {
                    SearchRoot = new DirectoryEntry(),
                    //start searching from local domain
                    Filter = "(&" +
                    "(objectClass=user)" +
                    "(name=" + UserName + "))" // This is Username
                };

                // start searching
                return ds.FindOne().GetDirectoryEntry();
            }
            catch (Exception ex)
            {
                throw new ApplicationException("error occured while querying AD");
            }
        }

检查帐户是否处于活动状态的方法

        private bool IsActive(DirectoryEntry de)
        {
            if (de.NativeGuid == null) return false;

            int flags = (int)de.Properties["userAccountControl"].Value;

            return !Convert.ToBoolean(flags & 0x0002);
        }

将用户保存到数据库的方法

        public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
        {
            DirectoryEntry userEntry = QueryAD(objSearchRolesViewModel.User_Id);
            if (userEntry == null) 
            {
               //Handle error where No User was Found.
               throw new ApplicationException("User Not Found");
            }

            USERACCOUNT objUserAccount = new USERACCOUNT
            {

                HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
                DOMAIN = "Aeth",
                NTUSERID = objSearchRolesViewModel.User_Id,
                ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
                FIRSTNAME = userEntry.Properties["givenname"].Value.ToString(), 
                LASTNAME = userEntry.Properties["sn"].Value.ToString(),
                EMAIL = userEntry.Properties["mail"].Value.ToString(),
                ACTIVE = IsActive(userEntry),
                DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
                CREATEID = userID,
                CREATEDATE = DateTime.Now,
                UPDATEID = userID,
                UPDATEDATE = DateTime.Now
            };
            _context.USERACCOUNTs.Add(objUserAccount);
            _context.SaveChanges();

        }

一些挑剔的事情:

打开连接

创建DirectoryEntry对象实际上并没有打开任何连接。 这就是几乎所有 Microsoft 库的工作方式:构造函数不发出任何 I/O 请求。 第一个网络请求是在您第一次开始使用该对象时发出的。

此外, new DirectoryEntry("")new DirectoryEntry() new DirectoryEntry("")具有完全相同的效果 - 空字符串不会给你任何东西。 而且,如果您不设置SearchRoot属性,它无论如何都会自动将其设置为当前域。 所以你甚至不需要设置它,除非你需要将它设置到不同的域或 OU。

现在来回答这个问题:

您已经得到了几个答案,但它们并不理想。 如果需要,您当然可以使用System.DirectoryServices.AccountManagement命名空间,它只是System.DirectoryServices的包装器,使事情变得更容易。 但就像所有让事情变得更容易的事情一样,它是以牺牲性能为代价的。 与您自己直接使用System.DirectoryServices ,它的性能总是更差。 一个原因是因为每当创建UserPrincipal对象时,它都会检索具有帐户值的每个属性 您可能没有使用每个属性。

如果您可以自己使用DirectoryEntry / DirectorySearcher ,您将拥有更好的代码性能。

Jawad 的答案也适用,但它有一个关键问题会减慢您的代码速度: DirectorySearcher将返回您请求的所有属性。 您已经设置了PropertiesToLoad ,这很好 - 它会将结果限制为仅您需要的属性。 但是,如果您使用GetDirectoryEntry() ,该信息将丢失。 如果您随后开始在DirectoryEntry上使用.Properties ,它将发出一个新的网络请求并请求所有具有值的属性 除了您可以避免的第二个网络请求之外,这可能是您没有使用的大量数据。

我建议只从QueryAD返回一个SearchResult ,这样您就可以使用搜索中返回的数据。

您也可以使用FindOne()而不是FindAll() ,因为无论如何您都只使用第一个结果。 这将使 AD 在找到一个结果后停止查找。 如果未找到用户,只需测试null

public SearchResult QueryAD(string userNID)
{
    DirectorySearcher ds = new DirectorySearcher(userNID) {
        PropertiesToLoad = {"givenname", "sn", "mail"}
    };

    return ds.FindOne();
}

public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
    var result = QueryAD(objSearchRolesViewModel.NID);

    if (result == null)
    {
        //user wasn't found!
    }

    USERACCOUNT objUserAccount = new USERACCOUNT
        {
            HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
            DOMAIN = "Aeth",
            NTUSERID = objSearchRolesViewModel.User_Id,
            ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
            FIRSTNAME = (string) result.Properties["givenName"]?[0],
            LASTNAME = (string) result.Properties["sn"]?[0],
            EMAIL = (string) result.Properties["mail"]?[0],
            ACTIVE = true/*Convert.ToBoolean(objSearchRolesViewModel.ActiveStatus)*/,
            DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
            CREATEID = userID,
            CREATEDATE = DateTime.Now,
            UPDATEID = userID,
            UPDATEDATE = DateTime.Now
        };

    _context.USERACCOUNTs.Add(objUserAccount);
    _context.SaveChanges();
}

SearchResultProperties将始终以数组的形式呈现属性,即使它们是 AD 中的单值属性。 这与DirectoryEntry不同。 但是,这是对的原因[0]result.Properties["givenName"]?[0] as string ? 是测试null ,因为如果属性没有在 AD 中设置,那么它根本不会出现在Properties集合中。

我写了一篇关于在使用 AD 编程时获得更好性能的文章,重点是 C#。 你可能会喜欢阅读它。

暂无
暂无

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

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