做企业应用开发难免会跟 AD 打交道,在之前的 dotNET FrameWork 时代,通常使用 System.DirectoryServices 的相关类来操作 AD ,在 dotNET Core 中没有这个命名空间,在张善友大佬的推荐下,知道了 Novell.Directory.Ldap。

操作 AD,通常有两种常见的场景:

  • 将第三方数据源数据(人事系统)同步到 AD 中

  • 将 AD 数据同步到自己的数据库中

本文将介绍在 dotNET Core 中使用 Novell.Directory.Ldap 将 AD 数据同步到数据库的操作。

环境

  • dotNET Core:2.1

  • Novell.Directory.Ldap.NETStandard2_0:3.1.0

安装 Novell.Directory.Ldap 包

在 VS2019 中添加 NuGet 包引用,如下图:

安装完成后,在类中添加using Novell.Directory.Ldap;引用便可使用相关的 API 方法了。

同步思路

1、连接 AD

基本操作

同步方法

public bool Sync()
{ADConnect();if (_connection == null){throw new Exception("AD连接错误,请确认AD相关信息配置正确!");}bool result = true;List<LdapEntry> entryList = this.GetRootEntries(_adPaths, _adHost);_org = new Org();_user = new User();Org rootOrg = _org.GetRootOrg();foreach (LdapEntry entry in entryList){SyncDirectoryEntry(entry, rootOrg, entry);}return result;
}

连接 AD

public bool ADConnect()
{_adHost = "192.168.16.160";string adAdminUserName = "administrator";string adAdminPassword = "123456";_adPaths =new string[] { "OU=oec2003,DC=COM,DC=cn" };if ((string.IsNullOrEmpty(_adHost) || string.IsNullOrEmpty(adAdminUserName)) ||string.IsNullOrEmpty(adAdminPassword)){return false;}try{_connection = new LdapConnection();_connection.Connect(_adHost, LdapConnection.DEFAULT_PORT);_connection.Bind(adAdminUserName, adAdminPassword);}catch{return false;}return true;
}

递归操作

private void SyncDirectoryEntry(LdapEntry rootEntry, Org parentOrg, LdapEntry currentEntry)
{List<LdapEntry> entryList = currentEntry.Children(_connection);foreach (LdapEntry entry in entryList){if (entry.IsOrganizationalUnit()){Org org = this.SyncOrgFromEntry(rootEntry, parentOrg, entry);this.SyncDirectoryEntry(rootEntry, org, entry);}else if (entry.IsUser()){this.SyncUserFromEntry(rootEntry, parentOrg, entry);}}
}

同步部门

private Org SyncOrgFromEntry(LdapEntry rootEntry, Org parentOrg, LdapEntry entry)
{string orgId = entry.Guid().ToLower();Org org = this._org.GetOrgById(orgId) as Org;if (org != null){if (entry.ContainsAttr("ou")){org.Name = entry.getAttribute("ou").StringValue + string.Empty;}//设置其他属性的值_org.UpdateOrg(org);return org;}org = new Org{Id = orgId,ParentId = parentOrg.Id,};//设置其他属性的值this._org.AddOrg(org);return org;
}

同步用户

private User SyncUserFromEntry(LdapEntry rootEntry, Org parentOrg, LdapEntry entry)
{string userId = entry.Guid().ToLower();User user = this._user.GetUserById(userId);if (user != null){user.ParentId = parentOrg.Id;//设置其他属性的值this._user.UpdateUser(user);return user;}user = new User{Id = userId,ParentId = parentOrg.Id};//设置其他属性的值this._user.AddUser(user);return user;
}

辅助方法

为了方便代码的编写和复用,将一些操作提取到了扩展方法中。

获取 Entry 的 GUID

public static string Guid(this LdapEntry entry)
{var bytes = (byte[])(entry.getAttribute("objectGUID").ByteValue as object);var guid = new Guid(bytes);return guid.ToString();
}

获取 Entry 的 子级

public static List<LdapEntry> Children(this LdapEntry entry, LdapConnection connection)
{//string filter = "(&(objectclass=user))";List<LdapEntry> entryList = new List<LdapEntry>();LdapSearchResults lsc = connection.Search(entry.DN, LdapConnection.SCOPE_ONE, "objectClass=*", null, false);if (lsc == null) return entryList;while (lsc.HasMore()){LdapEntry nextEntry = null;try{nextEntry = lsc.Next();if (nextEntry.IsUser() || nextEntry.IsOrganizationalUnit()){entryList.Add(nextEntry);}}catch (LdapException e){continue;}}return entryList;
}

判断 Entry 是否为用户

public static bool IsUser(this LdapEntry entry)
{return entry.ObjectClass().Contains("user");
}

判断 Entry 是否为部门

public static bool IsOrganizationalUnit(this LdapEntry entry)
{return entry.ObjectClass().Contains("organizationalunit");
}

获取 Entry 的修改时间

public static DateTime WhenChanged(this LdapEntry entry)
{string value = entry.getAttribute("whenChanged").StringValue;if (value.Split('.').Length > 1){value = value.Split('.')[0];}DateTime whenChanged = DateTime.ParseExact(value, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);return whenChanged;
}

判断 Entry 中属性是否存在

public static bool ContainsAttr(this LdapEntry entry, string attrName)
{LdapAttribute ldapAttribute = new LdapAttribute(attrName);return entry.getAttributeSet().Contains(ldapAttribute);
}

根据名称获取 Entry 中的属性值

public static string AttrStringValue(this LdapEntry entry, string attrName)
{if (!entry.ContainsAttr(attrName)){return string.Empty;}return entry.getAttribute(attrName).StringValue;
}

总结

文中没有做更多文字性的介绍,可以从下面链接中下载代码进行调试就很容易理解了。

参考

示例代码:https://github.com/oec2003/StudySamples/tree/master/DotNetCoreAdDemo/DotNetCoreAdDemo

祝大家国庆假期快乐!

dotNET Core 中怎样操作 AD?相关推荐

  1. dotNET Core 中怎样操作AD(续1)

    在之前的文章<dotNET Core 中怎样操作 AD?>中主要以AD的数据同步到数据库的场景来描述了在 dotNetCore 中怎样操作AD,本文将继续介绍一些在 dotNetCore ...

  2. 依赖注入在 dotnet core 中实现与使用:1 基本概念

    关于 Microsoft Extension: DependencyInjection 的介绍已经很多,但是多数偏重于实现原理和一些特定的实现场景.作为 dotnet core 的核心基石,这里准备全 ...

  3. 依赖注入在 dotnet core 中实现与使用:2 使用 Extensions DependencyInjection

    既然是依赖注入容器,必然会涉及到服务的注册,获取服务实例,管理作用域,服务注入这四个方面. 服务注册涉及如何将我们的定义的服务注册到容器中.这通常是实际开发中使用容器的第一步,而容器本身通常是由框架来 ...

  4. dotNET Core:编码规范

    在项目开发过程中,由于时间紧.任务重,很容易导致面向功能编程.实现相同的功能,代码可以写的很优雅,也可以写的很晦涩和复杂.现在的工作,都需要进行团队协作,代码就需要有一定的规范进行指引,因为我们需要写 ...

  5. dotNet Core 3.1 使用 Aspose (部署 Docker)

    在之前的文章<dotNET Core中使用Aspose(部署Docker)>中介绍了在 dotNet Core2.1 中使用 Aspose ,并部署到 Docker 中,现在 dotNET ...

  6. dotNET Core 3.X 使用 Autofac 来增强依赖注入

    在上一篇<dotNET Core 3.X 依赖注入>中简单介绍了 dotNET Core 框架本身的依赖注入功能,大部分情况下使用框架的依赖注入功能就可以满足了,在一些特殊场景下,我们就需 ...

  7. dotNET Core 3.X 依赖注入

    如果说在之前的 dotNET 版本中,依赖注入还是个比较新鲜的东西,那么在 dotNET Core 中已经是随处可见了,可以说整个 dotNET Core 的框架是构建在依赖注入框架之上.本文说说对 ...

  8. dotNET Core 3.X 请求处理管道和中间件的理解

    理解 dotNET Core 中的管道模型,对我们学习 dotNET Core 有很大的好处,能让我们知其然,也知其所以然,这样在使用第三方组件或者自己写一些扩展时,可以避免入坑,或者说避免同样的问题 ...

  9. 使用Novell.Directory.Ldap.NETStandard在.NET Core中验证AD域账号

    Novell.Directory.Ldap.NETStandard是一个在.NET Core中,既支持Windows平台,又支持Linux平台,进行Windows AD域操作的Nuget包. 首先我们 ...

最新文章

  1. AI洞观 | 一文读懂英特尔的AI之路
  2. 2020-12-09 深度学习 卷积核/过滤器、特征图(featue map)、卷积层
  3. liunx 加入域控_让Linux使用Windows域控制器做用户认证
  4. 牛客网暑期ACM多校训练营(第三场)H - Diff-prime Pairs
  5. 升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署
  6. P1020 导弹拦截(n*log n时间的最长上升子序列思想)
  7. Linux 设备驱动模型中的class(类)
  8. file 选择的图片作为背景图片_酷炫!用Python把桌面变成实时更新的地球图片
  9. RabbitMQ 最新版安装 (Linux环境)
  10. 跟随者数字解码_跟随模式的数字
  11. mysql 重复了更新_MYSql id相同就更新
  12. netcore之hello
  13. SQL Server里面如何检查没有释放的游标
  14. 蜂鸣器播放青鸟,含曲谱(小萌白新文)
  15. OpenKG祝大家端午安康
  16. 单片机(51) 什么是编码器?什么是译码器?
  17. 瑞吉外卖01-项目整体介绍
  18. 3D简单壳体CAD绘制
  19. 【学习OpenCV4】案例3:OpenCV Python语言开发环境搭建
  20. python人力成本数据测算_人力成本分析计算公式大全

热门文章

  1. linkButton与Button 的click事件与onclientClick事件
  2. excel if in函数_【Excel函数】Small+Index+IF 一对N返回
  3. python博客访问量_史诗级干货-python爬虫之增加CSDN访问量
  4. 绘制三维散点图_SPSS统计作图教程:三维散点图
  5. 学go语言能做什么工作?
  6. 补充一点地理知识(以洲来划分各个国家(240个))
  7. mongoDB的副本机制
  8. DCOS实践分享(6):基于DCOS的大数据应用分享
  9. Visual Entity 手册(十一)代码生成设置
  10. DBDesigner 4 与 MySql 5 不能连接主要是驱动的原因