.NET/C#操作AD域与OpenLDAP

最近公司有需求要同时对接AD域和OpenLDAP,把OpenLDAP的组织和员工数据同步到AD域中,于是去网上找了很多资料,大多数都不全或者有问题,后面我一步步摸索出来了自己的经验,现在分享出来。

分享的内容为主流程代码,采用.net core 3.1+Quartz定时服务+Ad域+OpenLDAP+对接钉钉部分功能完成的。其他代码因为可能涉及公司著作权的问题就不贴了,有疑问可以评论文章问我。部分LDAPHelper的内容采用了其他博客的部分代码。注意,虽然下面代码是用.net core开发的,但是只支持部署到windows,因为System.DirectoryServices只支持windows平台,不支持linux平台,若要支持linux,则不能使用System.DirectoryServices及其内部函数,得使用linux专用的操作目录服务器的.net core sdk,具体是哪个sdk大家可以去搜索下。

废话不多说直接上代码:

using Quartz;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using log4net;
using ZT.Log;
using System.DirectoryServices;
using ZT.DataSyncService.HRToContract.Helper;
using ZT.DataSyncService.HRToContract.Entity;
using System.Linq;
using System.Net.Mail;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using DingTalk.Api;
using DingTalk.Api.Request;
using DingTalk.Api.Response;

namespace ZT.DataSyncService.HRToContract.Jobs
{
    [DisallowConcurrentExecution]
    public class AdLDAPJob : IJob
    {
        public static List<SendEmailEmployee> newEmployees = new List<SendEmailEmployee>();
        private static LdapHelper adHelper = null;
        private static LdapHelper openHelper = null;

        //预警人数统计
        private static int W_AddUserCount = 0;
        private static int W_DisUserCount = 0;
        //常规人数统计
        private static int I_AddUserCount = 0;
        private static int I_MoveUserCount = 0;
        private static int I_DisUserCount = 0;
        private static DateTime I_LastSendTime = DateTime.MinValue;

        private ILog log = LogManager.GetLogger(Program.repository.Name, typeof(AdLDAPJob));

        public Task Execute(IJobExecutionContext context)
        {
            try
            {
                log.Info("AdLDAPJob运行开始");
                RunFunc();
                log.Info("AdLDAPJob运行结束");
            }
            catch (Exception ex)
            {
                log.Error("AdLDAPJob/Execute异常", ex);
            }
            return Task.CompletedTask;
        }

        public void RunFunc()
        {
            var adDomain = AppConfigurtaionServices.Configuration.GetSection("AdLDAP:adDomain").Value;
            var adDomain2 = AppConfigurtaionServices.Configuration.GetSection("AdLDAP:adDomain2").Value;
            var adIP = AppConfigurtaionServices.Configuration.GetSection("AdLDAP:adIP").Value;
            var adUser = AppConfigurtaionServices.Configuration.GetSection("AdLDAP:adUser").Value;
            var adPassword = AppConfigurtaionServices.Configuration.GetSection("AdLDAP:adPassword").Value;

            var openDomain = AppConfigurtaionServices.Configuration.GetSection("OpenLDAP:openDomain").Value;
            var openDomain2 = AppConfigurtaionServices.Configuration.GetSection("OpenLDAP:openDomain2").Value;
            var openIP = AppConfigurtaionServices.Configuration.GetSection("OpenLDAP:openIP").Value;
            var openUser = AppConfigurtaionServices.Configuration.GetSection("OpenLDAP:openUser").Value;
            var openPassword = AppConfigurtaionServices.Configuration.GetSection("OpenLDAP:openPassword").Value;

            var companyName = AppConfigurtaionServices.Configuration.GetSection("CompanyName").Value;
            companyName = string.IsNullOrEmpty(companyName) ? "XX网络" : companyName;

            adHelper = new LdapHelper(adDomain, adDomain2, adIP, adUser, adPassword);
            openHelper = new LdapHelper(openDomain, openDomain2, openIP, openUser, openPassword);

            DirectoryEntry entry = new DirectoryEntry(adHelper.GetDomainPath(), adUser, adPassword, AuthenticationTypes.Secure);
            var companyEntry = new DirectoryEntry();
            companyEntry = ExistChildrenOU(entry, companyName);

            if (companyEntry == null)
            {
                companyEntry = entry.Children.Add("OU=" + companyName, "organizationalUnit");
                companyEntry.CommitChanges();
            }

            DirectoryEntry openEntry = new DirectoryEntry(openHelper.GetDomainPath(), openUser, openPassword, AuthenticationTypes.None);
            DirectoryEntry openCompanyEntry = ExistChildrenOU(openEntry, companyName);

            //getAllUser(openCompanyEntry, companyName);

            //同步新增组织
            addOrgEntry(companyEntry, openCompanyEntry);

            //同步新增、修改、移动用户
            addUserEntry(companyEntry, openCompanyEntry, companyName);

            //同步禁用离职用户
            disUserEntry(companyEntry, openCompanyEntry, companyName);

            //同步删除不存在的组织(暂时不考虑删除操作)
            //delOrgEntry(companyEntry, openCompanyEntry);

            //发送新员工邮件给指定人
            if (newEmployees.Count > 0)
            {
                SendNewEmployeesEmail();
            }

            //钉钉群机器人预警推送
            DingWarning();
        }
        #region 工具函数
        public void DingWarning()
        {
            try
            {
                var warningCount = Convert.ToInt32(AppConfigurtaionServices.Configuration.GetSection("Warning:warningCount").Value);

                if (W_AddUserCount >= warningCount)
                {
                    //发钉钉机器人
                    SendDingRobotMsg("【新增提醒】\n过去1分钟内程序同步新增了" + W_AddUserCount + "名员工\n请管理员确认是否存在问题!");
                }

                if (W_DisUserCount >= warningCount)
                {
                    //发钉钉机器人
                    SendDingRobotMsg("【禁用提醒】\n过去1分钟内程序同步禁用了" + W_DisUserCount + "名员工\n请管理员确认是否存在问题!");
                }

                W_AddUserCount = 0;
                W_DisUserCount = 0;

                var now = DateTime.Now;
                if (now.Hour == 17 && now.Minute >= 0 && now.Minute < 5 && I_LastSendTime.ToString("yyyyMMdd") != now.ToString("yyyyMMdd"))
                {
                    //发钉钉机器人
                    SendDingRobotMsg("【统计提醒】\n" + now.AddDays(-1).ToString("yyyy/MM/dd") + "-" + now.ToString("yyyy/MM/dd") + "\n入职新增" + I_AddUserCount + "人\n跨部门移动" + I_MoveUserCount + "人\n离职禁用" + I_DisUserCount + "人", false);
                    //更新最后发送时间,一天只发一次
                    I_LastSendTime = now;
                    I_AddUserCount = 0;
                    I_MoveUserCount = 0;
                    I_DisUserCount = 0;
                }
            }
            catch (Exception ex)
            {
                log.Error("DingWarning异常", ex);
            }
        }


        /// <summary>
        /// 获取openldap所有员工,并构造出一级部门
        /// </summary>
        /// <param name="openEntry"></param>
        /// <param name="companyName"></param>
        public void getAllUser(DirectoryEntry openEntry, string companyName)
        {
            if (openEntry.Children != null)
            {
                foreach (DirectoryEntry orgChildren in openEntry.Children)
                {
                    if (orgChildren.Name.Contains("cn="))
                    {
                        Console.WriteLine(orgChildren.Name);
                    }
                }

                foreach (DirectoryEntry orgChildren in openEntry.Children)
                {
                    if (orgChildren.Name.Contains("ou="))
                    {
                        getAllUser(orgChildren, companyName);
                    }
                }
            }
        }

        /// <summary>
        /// 启用所有被禁用的用户
        /// </summary>
        /// <param name="adEntry"></param>
        /// <param name="companyName"></param>
        public void qyUserEntry(DirectoryEntry adEntry, string companyName)
        {
            try
            {
                if (adEntry.Children != null)
                {
                    foreach (DirectoryEntry adChildren in adEntry.Children)
                    {
                        if (adChildren.Name.Contains("CN=") && adChildren.Properties["userAccountControl"].Value.ToString() != "512")
                        {
                            //512是启用
                            adChildren.Properties["userAccountControl"].Value = 512;

                            //adChildren.Invoke("SetPassword", new object[] { "abc123!" });

                            adChildren.CommitChanges();

                            LogTxtHelper.CreateInLog(adChildren.Name + ",时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                        }
                    }

                    foreach (DirectoryEntry adChildren in adEntry.Children)
                    {
                        if (adChildren.Name.Contains("OU="))
                        {
                            qyUserEntry(adChildren, companyName);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogTxtHelper.CreateInLog("qyUserEntry异常,时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "," + JsonConvert.SerializeObject(ex));
            }
        }

        /// <summary>
        /// 添加组织到AD
        /// </summary>
        /// <param name="entry"></param>
        /// <param name="org"></param>
        public void addOrgEntry(DirectoryEntry entry, DirectoryEntry openEntry)
        {
            try
            {
                if (openEntry.Children != null)
                {
                    foreach (DirectoryEntry orgChildren in openEntry.Children)
                    {
                        if (ExistChildrenOU(entry, orgChildren.Name.Replace("ou=", "")) == null && orgChildren.Name.Contains("ou="))
                        {
                            var orgEntry = entry.Children.Add(orgChildren.Name, "organizationalUnit");
                            orgEntry.CommitChanges();
                        }
                    }

                    foreach (DirectoryEntry orgChildren in openEntry.Children)
                    {
                        if (orgChildren.Name.Contains("ou="))
                        {
                            var childEntry = entry.Children.Find(orgChildren.Name);
                            addOrgEntry(childEntry, orgChildren);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                log.Error("addOrgEntry异常", ex);
            }
        }

        /// <summary>
        /// 添加、修改、移动用户到AD
        /// </summary>
        /// <param name="entry"></param>
        /// <param name="org"></param>
        public void addUserEntry(DirectoryEntry entry, DirectoryEntry openEntry, string companyName)
        {
            try
            {
                if (openEntry.Children != null)
                {
                    foreach (DirectoryEntry orgChildren in openEntry.Children)
                    {
                        if (orgChildren.Name.Contains("cn="))
                        {
                            //ad员工
                            var domainUser = new DomainUser()
                            {
                                UserId = orgChildren.Name.Replace("cn=", ""),
                                Email = orgChildren.Properties["mail"].Value?.ToString(),
                                UserName = orgChildren.Properties["displayName"].Value?.ToString(),
                                Telephone = orgChildren.Properties["mobile"].Value?.ToString(),
                                Title = orgChildren.Properties["Title"].Value?.ToString()
                            };

                            var openPath = orgChildren.Path;

                            var adUser = adHelper.GetUser(adHelper.GetDomainPath2(companyName), orgChildren.Name.Replace("cn=", ""));

                            var openPathW = openHelper.GetTailPath(openPath);
                            //1.如果在ad中存在此用户
                            if (adUser != null)
                            {
                                var adPath = adUser.Path.Replace("\\", "");
                                var adPathW = adHelper.GetTailPath(adPath);
                                //1.1.如果open的完整path和ad的完整path相同,则更新
                                if (adPathW.ToUpper() == openPathW.ToUpper())
                                {
                                    adPath = adHelper.GetAllPathByTailPath(openPathW, false);
                                    adHelper.EditADAccount(adPath, domainUser);
                                }
                                //1.2.如果open的完整path和ad的完整path不相同,则转移到db的path里
                         
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值