html5移动端手机网站开发流程图,网站建设速成,建设网站经营范围,网站建设ftp前言
嗨#xff0c;大家好#xff01;
在这个数据信息飞速发展的 21 世纪#xff0c;数据安全成为了每个企业关注的焦点#xff0c;保护企业数据安全日益成为企业工作中的重中之重。
域服务器#xff0c;尤其是微软的 Active Directory#xff08;AD#xff09;…
前言
嗨大家好
在这个数据信息飞速发展的 21 世纪数据安全成为了每个企业关注的焦点保护企业数据安全日益成为企业工作中的重中之重。
域服务器尤其是微软的 Active DirectoryAD因其显著的安全优势已成为不少企业的首选。
简单来说域服务器就是一个 “超级管理员”它可以集中管理网络中的所有用户、计算机和其他资源。
通过域服务器企业可以轻松地为用户分配和管理权限确保数据安全也可以通过组策略统一管理网络中所有计算机的设置和安全策略更好地保护敏感信息。
域服务器天然就是一个企业员工信息的数据库将业务系统的身份鉴权跟域服务器紧密结合无疑已经成为安全技术发展的趋势。
C# 拥有丰富的类库来与 Active DirectoryAD互动但使用时很不方便因此我根据项目的实际业务需求造了一个轮子封装了一些常用的操作 AD 的方法简化了与 AD 的交互用起来还挺方便的。
今天我很高兴与大家分享这些便利希望能让你的开发之旅充满乐趣和效率
下面让我们一起来看看具体的实现步骤吧
Step By Step 代码
1. 创建配置文件
首先需要创建一个配置文件如 LDAPConfig.config用于保存域的相关配置信息内容如下
?xml version1.0 encodingutf-8 ?
LDAPConfigurationHostURL192.168.0.120:389/URLLoginDNCNcorp_test,CNUsers,DCjacky,DCcom/LoginDNPassword6nkUhDs5lmcfMYS/qe7Qw/Password/HostUserSearchSearchBaseOU某某市软件技术有限公司,DCcorp,DCcom/SearchBaseSearchFilter(amp;(objectClassPerson)(sAMAccountName{0}))/SearchFilterUserAttributesAMAccountName,memberOf,displayName/UserAttribute/UserSearchAdminGroupAndoErp_Administrators/AdminGroup
/LDAPConfiguration2. 创建配置文件实体类
接下来创建一个配置文件实体类 LDAPConfigModel读取和解析配置文件中的信息留意注释
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Common.Util;namespace Common.Model
{[XmlRoot(LDAPConfiguration)]public class LDAPConfigModel{/// summary/// AD/LDAP 服务器和绑定帐号配置/// /summary[XmlElement(Host)]public LdapHostSetting LdapHost { get; set; }/// summary/// 用户搜索配置/// /summary[XmlElement(UserSearch)]public UserSearchSetting UserSearch { get; set; }/// summary/// 管理员组/// /summarypublic string AdminGroup { get; set; }}public class LdapHostSetting{/// summary/// AD/LDAP 服务器 URL/// /summarypublic string URL { get; set; }/// summary/// 绑定帐号的 distinguished name/// /summarypublic string LoginDN { get; set; }/// summary/// 绑定帐号的密码(加密状态)/// /summarypublic string Password { get; set; }/// summary/// 绑定帐号的密码/// /summary[XmlIgnore]public string SafePassword{get { return EncryptUtil.AESDecode(Password); }set { Password EncryptUtil.AESEncode(value); }}}public class UserSearchSetting{/// summary/// 搜索路径/// /summarypublic string SearchBase { get; set; }/// summary/// 搜索过滤器/// /summarypublic string SearchFilter { get; set; }/// summary/// 搜索属性/// /summarypublic string UserAttribute { get; set; }}
}3. 创建一个域常用操作方法的封装类
然后创建一个名为 LdapUtil 的静态类封装所有与域相关的操作方法重点留意代码注释
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.DirectoryServices.Protocols;
using Common.Model;
using System.Net;
using Ando.ERP.Logger;
using System.IO;
using System.Reflection;namespace Common.Util
{/// summary/// 域 LDAP/AD 常用操作方法封装类/// /summarypublic static class LdapUtil{static readonly LDAPConfigModel ldapConfig null;/// summary/// 静态构造方法读取配置文件初始化 ldapConfig 对象/// /summarystatic LdapUtil(){if (ldapConfig ! null) return;string ldapConfigPath;if (AppDomain.CurrentDomain.SetupInformation.PrivateBinPath ! null)ldapConfigPath Path.Combine(AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, ConfigFile, LDAPConfig.config);elseldapConfigPath Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFile, LDAPConfig.config);if (!File.Exists(ldapConfigPath)){Assembly myAssembly Assembly.GetExecutingAssembly();FileInfo dllFile new FileInfo(myAssembly.Location);string path dllFile.Directory.FullName;ldapConfigPath Path.Combine(path, ConfigFile, LDAPConfig.config);}ldapConfig ConfigUtil.DeserializeLDAPConfigModel(ldapConfigPath);}#region common private method/// summary/// 连接域服务器/// /summary/// param nameloginDN域用户/param/// param nameloginPassword域用户密码/param/// param nameldapConnectionLdapConnection 对象/paramprivate static void Connect(string loginDN, string loginPassword, ref LdapConnection ldapConnection){var networkCredential new NetworkCredential(loginDN, loginPassword);ldapConnection.SessionOptions.SecureSocketLayer false;ldapConnection.SessionOptions.ProtocolVersion 3;ldapConnection.AuthType AuthType.Basic;ldapConnection.Credential networkCredential;ldapConnection.Bind();}/// summary/// para通过 LDAP 配置信息连接域服务器/para/// para如果参数 cLoginDN 不为空使用 cLoginDN 作为 loginDN/para/// para如果参数 cLoginPassword 不为空使用 cLoginPassword 作为 loginPassword/para/// /summary/// param nameldapConfig/param/// param nameldapConnection/param/// param namecLoginDN/param/// param namecLoginPassword/paramprivate static void Connect(ref LdapConnection ldapConnection, string cLoginDN , string cLoginPassword ){string loginDN string.IsNullOrEmpty(cLoginDN) ? ldapConfig.LdapHost.LoginDN : cLoginDN;string loginPassword string.IsNullOrEmpty(cLoginPassword) ? ldapConfig.LdapHost.SafePassword : cLoginPassword;AndoErpLogger.DEFAULT.DebugFormat(Connecting to LDAP/AD server [{0}] with account [{1}], ldapConfig.LdapHost.URL, loginDN);Connect(loginDN, loginPassword, ref ldapConnection);}/// summary/// 通过 Action 执行一些自定义操作LDAP Util 核心方法/// /summary/// param nameldapConfig/param/// param namecLoginDN/param/// param namecLoginPassword/param/// param namefunc/paramprivate static void LDAPCore(string cLoginDN, string cLoginPassword, ActionLdapConnection action){LdapConnection ldapConnection null;try{ldapConnection new LdapConnection(ldapConfig.LdapHost.URL);Connect(ref ldapConnection, cLoginDN, cLoginPassword);action(ldapConnection);}catch{throw;}finally{if (ldapConnection ! null) ldapConnection.Dispose();}}/// summary/// 通过用户搜索配置搜索域数据/// /summary/// param nameldapConnection/param/// param namesizeLimit指定返回的实体数/param/// param namesearchPath搜索路径/param/// param namefilter过滤字符串/param/// param nameisSubtree是否深度搜索/param/// param nameattrs搜索属性/paramprivate static SearchResultEntryCollection Search(LdapConnection ldapConnection, int sizeLimit, string searchPath, string filter, params string[] attrs){try{SearchRequest request new SearchRequest(searchPath, filter, SearchScope.Subtree, attrs);if (sizeLimit 0) request.SizeLimit sizeLimit;SearchResponse response (SearchResponse)ldapConnection.SendRequest(request);return response.Entries;}catch (DirectoryOperationException e){// 返回此异常中已处理的所有数据// 因为 LDAP/AD 搜索默认在 1000 以内超过就会报这个错SearchResponse response (SearchResponse)e.Response;return response.Entries;}catch (Exception ex){throw;}}#endregion#region business method/// summary/// 获取指定域用户的 distinguished name 值/// /summary/// param nameldapConfig/param/// param nameuserName/param/// returns/returnsprivate static LdpaUserInfo GetLDAPUserDN(string userName){var ldpaUser new LdpaUserInfo();LDAPCore(null, null, (ldapConnection) {var userEntries GetUserEntries(ldapConnection, userName, 50);var userEntry userEntries[0];ldpaUser.UserDN userEntry.DistinguishedName;ldpaUser.UserGroupList GetAttributeValues(userEntry, memberOf);ldpaUser.UserDisplayName GetAttributeValues(userEntry, displayName)[0];});return ldpaUser;}/// summary/// 获取用户搜索配置中的所有域帐户实体/// /summary/// param nameldapConfig/param/// param nameldapConnection/param/// param nameuserName/param/// param namesizeLimit/param/// returns/returnsprivate static SearchResultEntryCollection GetUserEntries(LdapConnection ldapConnection, string userName, int sizeLimit){string userSearchBasePath ldapConfig.UserSearch.SearchBase;string userSearchFilter ldapConfig.UserSearch.SearchFilter;string[] userAttribute ldapConfig.UserSearch.UserAttribute.Split(,);if (!string.IsNullOrEmpty(userName)){userSearchFilter string.Format(userSearchFilter, userName);}var userEntries Search(ldapConnection, sizeLimit, userSearchBasePath, userSearchFilter, userAttribute);if (userEntries null || userEntries.Count 0){string exceptionMsg string.Format(没有找到符合条件的域用户请检查用户搜索配置。搜索路径: [{0}], 过滤条件: [{1}], userSearchBasePath, userSearchFilter);throw new LdapException(exceptionMsg);}return userEntries;}/// summary/// 获取域帐户实体配置中的属性的值/// /summary/// param nameentry/param/// param nameattributeName/param/// returns/returnsprivate static Liststring GetAttributeValues(SearchResultEntry entry, string attributeName){var attributes entry.Attributes;var attributeObj attributes[attributeName];if (attributeObj null){return null;}Liststring valueList new Liststring(); var attributeValues attributes[attributeName].GetValues(typeof(string));foreach (var attributeValue in attributeValues){valueList.Add(CommonUtil.TranNullstring(attributeValue));}return valueList;}/// summary/// 检查登录帐户是否存在域中/// /summary/// param nameuserName/param/// param namepassword/param/// param nameldapConfig/param/// returns/returnspublic static bool IsExistLDAPUser(string userName, string password, out bool isAdministrator, out string userDisplayName){bool result false;bool userIsAdmin false;string userShowName string.Empty;try{var ldpaUser GetLDAPUserDN(userName);string userDN ldpaUser.UserDN;userShowName ldpaUser.UserDisplayName;LDAPCore(userDN, password, (ldapConnection) {if (ldpaUser.UserGroupList null || ldpaUser.UserGroupList.Count 0)userIsAdmin false;else{var findResult ldpaUser.UserGroupList.First(x x.IndexOf(ldapConfig.AdminGroup, StringComparison.OrdinalIgnoreCase) 0);if (string.IsNullOrEmpty(findResult))userIsAdmin false;elseuserIsAdmin true;}result true;});}catch (Exception ex){// TODO 可将错误信息写到日志中方便排查原因result false;}isAdministrator userIsAdmin;userDisplayName userShowName;return result;}/// summary/// 获取用户搜索配置中的所有域帐户的 displayName 的值/// /summary/// param nameldapConfig/param/// param nameuserName/param/// returns/returnspublic static Liststring GetAllUsers(){var list new Liststring();LDAPCore(null, null, (ldapConnection) {var userEntries GetUserEntries(ldapConnection, *, 350);foreach (var userEntry in userEntries){var userDisplayName GetAttributeValues((SearchResultEntry)userEntry, displayName)[0];list.Add(userDisplayName);}});return list;}#endregion#region Inner class/// summary/// 域用户基本信息/// /summarysealed class LdpaUserInfo{public string UserDN { get; set; }public Liststring UserGroupList { get; set; }public string UserDisplayName { get; set; }}#endregion}
}4. 使用示例
最后我们来看一下如何使用这个封装类来执行一些基本操作比如登录
/// summary
/// 登录
/// /summary
/// param nameuserName/param
/// param namepassword/param
/// returns/returns
public void Login(string userName, string password)
{var hasUser LdapUtil.IsExistLDAPUser(userName, password, out bool isAdministrator, out string userDisplayName);if (hasUser){// 域用户存在登录成功继续处理后续业务}else{// 域用户不存在登录失败}
}总结
好了今天的分享就到这里啦
通过以上的封装我们可以更高效地与 Active Directory 进行交互无论是用户的身份验证、信息查询还是其他操作这些方法都能帮助简化代码提高开发效率你可以把它用在自己的项目里根据自己的实际业务需求继续添加新的业务处理方法或删减其中一些方法
随着数字化进程的加速越来越多的企业转向域服务器来高效管理网络环境C# 的灵活性和强大功能使其与 Active Directory 的结合成为了一种自然的选择希望这篇教程能够给你提供一些实用的操作方法和思路。
最后如果你有更好的想法或建议欢迎留言讨论
往期精彩
闲话 .NET7.NET Core 能淘汰 .NET FrameWork 吗常用的 4 种 ORM 框架EF CoreSqlSugarFreeSqlDapper对比总结 我是老杨一个执着于编程乐趣、至今奋斗在一线的 10年 资深研发老鸟是软件项目管理师也是快乐的程序猿持续免费分享全栈实用编程技巧、项目管理经验和职场成长心得欢迎关注老杨的公众号更多干货等着你