什么是LDAP
LDAP是轻量目录访问协议(Lightweight Directory Access Protocol)的缩写,LDAP是从X.500目录访问协议的基础上发展过来的,目前的版本是v3.0。与LDAP一样提供类似的目录服务软件还有ApacheDS、Active Directory、Red Hat Directory Service 。
LDAP的特点
LDAP作为一个是轻量目录服务软件,与关系型数据库不同,它有很好的读性能,当读写比大于7:1的时候,就可以考虑使用LDAP存储数据。但是写性能很差,所以不擅长处理频繁的修改的插入,并且没有事务处理、和回滚等功能。
LDAP提供静态数据的快速查询方式
Client/Server模型,Server 用于存储数据,Client提供操作目录信息树的工具
这些工具可以将数据库的内容以文本格式(LDAP 数据交换格式,LDIF)呈现在您的面前
LDAP是一种开放Internet标准,LDAP协议是跨平台的Interent协议
一般会将认证用户信息放在LDAP中,例如单位人员的信息,按照单位部门层级创建目录,并将人员信息存放在相应的目录下。但是因为目录服务不是像关系型数据库的表格结构,所以查询时不能使用SQL语句。
C#链接LDAP
本文中采用的是使用开源工具 Novell.Directory.Ldap ,可以在 Nuget 中下载包使用
还有一种比较简单的连接方式,安装使用 System.DirectoryServices 包,使用方法可以自行百度。
DirectoryServices 有一个优点,其读取并显示出的信息和 LDAP 中是一样的,基本不需要额外的转化操作。
比如 LDAP 中的 objectGUID一般是以 octetString 类型存储的,我们从 DirectoryEntry 中的 Properties 中获取的 objectGUID 和 LDAP 中的 objectGUID 是一致的,不存在乱码的情况
但是 Novell.Directory.Ldap 中读取的 obejctGUID 的 StringValue 会存在乱码的情况,但是其实际值是正确的,我们可以根据它返回的 ByteValue 自行解析
那么为什么不使用 DirectorySearcher呢?因为它不支持 LINUX 平台。
代码
在这做一个简单的接口
private string Domin = "aaa";//域名称
private string Host = "aaa.bb.cc";//域服务器地址
private int Port = 389;///端口
private string BaseDc = "DC=aaa,DC=bb,DC=cc";//根据上面的与服务器地址 拆分DC
private string User = "xxxxxx";//用户名
private string Password = "xxx";//密码
/// <summary>
/// 获取用户信息
/// </summary>
/// <param name="user">用户信息</param>
/// <returns>用户结果集</returns>
[HttpGet]
public Dictionary<string,object> GetUserByName(User user)
{
Dictionary<string, object> rs = new Dictionary<string, object>();
//用户结果集
List<User> result = new List<User>();
//默认响应结果
rs.Add("code", 500);
rs.Add("msg", "接口异常");
rs.Add("data", result);
rs.Add("success", false);
if (null != user)
{
try
{
//初始化链接
using (var ldapConnection = new LdapConnection())
{
//链接
ldapConnection.Connect(Host, Port);
//使用指定的认证信息发送 LDAP 绑定。
ldapConnection.Bind(Domin + "\\" + User, Password);
//过滤条件
string filter = "(&(objectClass=user)";
if (null != user.realname && !"".Equals(user.realname))
{
filter += "(name=*" + user.realname + "*)";
}
if (null != user.email && !"".Equals(user.email))
{
filter += "(mail=*" + user.email + "*)";
}
filter += ")";
//设置查询条件 在这里我们只要返回 用户 guid、name、mail就可以了
var entities = ldapConnection.Search(BaseDc, LdapConnection.ScopeSub,filter,new string[] { "objectGUID","name","mail"}, false);
//循环结果集
while (entities.HasMore())
{
try
{
LdapEntry entity = entities.Next();
User useri = new User();
foreach (var item in entity.GetAttributeSet()) {
if ("name"==item.Name)
{
useri.realname = item.StringValue;
}
else if("mail"==item.Name)
{
useri.email = item.StringValue;
}
else if ("objectGUID"==item.Name)
{
//处理objectGUID乱码
string guid = OctetStringToString(item.ByteValue) ;
useri.id = guid;
}
}
result.Add(useri);
}
catch (Exception ex)
{
}
}
rs["code"] = 200;
rs["msg"] = "";
rs["data"] = result;
rs["success"] = true;
}
}
catch (Exception err)
{
rs["msg"] = err.Message;
}
}
return rs;
}
/// <summary>
/// 网上找的方法
/// 解析拼接 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx
/// </summary>
/// <param name="GUID"></param>
/// <returns></returns>
private string OctetStringToString(byte[] GUID)
{
String strGUID = "";
String byteGUID = "";
for (int c = 0; c < GUID.Length; c++)
{
byteGUID = byteGUID + "\\" + AddLeadingZero((int)GUID[c] & 0xFF);
}
strGUID = "";
strGUID = strGUID + AddLeadingZero((int)GUID[3] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[2] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[1] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[0] & 0xFF);
strGUID = strGUID + "-";
strGUID = strGUID + AddLeadingZero((int)GUID[5] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[4] & 0xFF);
strGUID = strGUID + "-";
strGUID = strGUID + AddLeadingZero((int)GUID[7] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[6] & 0xFF);
strGUID = strGUID + "-";
strGUID = strGUID + AddLeadingZero((int)GUID[8] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[9] & 0xFF);
strGUID = strGUID + "-";
strGUID = strGUID + AddLeadingZero((int)GUID[10] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[11] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[12] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[13] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[14] & 0xFF);
strGUID = strGUID + AddLeadingZero((int)GUID[15] & 0xFF);
return strGUID;
}
/// <summary>
/// 长度不足补零
/// </summary>
/// <param name="k"></param>
/// <returns></returns>
private static String AddLeadingZero(int k)
{
return (k <= 0xF)?"0"+Int2String(k): Int2String(k);
}
/// <summary>
/// int 转 hexstring
/// </summary>
/// <param name="kb"></param>
/// <returns></returns>
private static string Int2String(int kb)
{
byte[] bytes = new byte[1];
bytes[0] = (byte)(kb & 0xFF);
string S = Convert.ToHexString(bytes);
return S;
}
Linux 安装.NetCore环境
因为我使用的是内网服务器,这里主要记录一下离线环境的配置,在线安装直接使用 yum instyall 安装各种环境即可
- 下载安装包 ,我选择的是 .NET 6.0.101 ,X64版本
https://dotnet.microsoft.com/en-us/download/dotnet/6.0
- LINUX 服务器创建文件夹
mkdir /home/dotnet
- 上传文件到创建的文件夹里面
- 解压文件
tar zxvf dotnet-sdk-6.0.101-linux-x64.tar.gz
- 创建软连接
ln -s /home/dotnet/dotnet /usr/bin
- 测试dotnet环境
dotnet --version
正常打印dotnet版本即表示安装成功。
.NetCore WebApi 部署
- 发布项目 打包到 myproject 文件夹
- 上传服务器 /home/dotnet_project 文件夹下
- 执行命令
dotnet /home/dotnet_project/myproject/myWebApi.dll
添加参数 --urls = http://0.0.0.0:8800 指定端口(可以在appSetting.json中配置 urls )
- 测试端口
curl http://127.0.0.1:8800/api/Ldap/get
curl -X POST --header “Content-Type: application/json” -d {“name”:“小明”} http://127.0.0.1:8800/api/Ldap/getUserByName