我从0开始开发了一个LDAP服务。
当然不能从0开始,,,我当初酝酿这个需求的时候,LDAP的rfc都看了一周。
需求是需要一个LDAP服务来支持三方系统的登录,比如神策、confluence、jira。
都不用想,三方开源闭源的方案都有很多。但是我寻觅了一圈,没找到一个可以直接在LDAP后端对接一个接口到账号体系的,都是需要账号导入,纳尼?
哈哈哈,也或许是造轮子的情绪太重,没有认真的找。但是不管怎么样,轮子造出来了。
我是怎么造的轮子?
当然是先读书了,rfc是要读个大概的。
https://www.cnblogs.com/mrtiny/p/ldap-Technical-Specification-Road-Map.html
协议指令比较多,我们并不关心用不到的,我们只需要支持两个主要的指令,查询(searchrequest)、认证(bindrequest)
就可以实现需求了。
LDAP的服务端实现有很多,我选了一个叫OpenLDAP的,因为名字看着顺眼。
源码是C++的,我开始是用它的数据库结构,并参考代码,用C#实现了对应的账号管理功能,当时的方案是认证时候同步账号到ldap数据库。
协议解析,也就是将请求数据解析成程序员能看明白的实体对象,也是有开源方案的。
比如Zetetic的,http://wiki.github.com/skradel/Zetetic.Ldap。
实际使用时候,发现有很多不完善,解析出错。因此我基于rfc和它的一些类的定义实现了自己的方案。
主要就是将请求解析成Asn1,然后从Asn1解析出实体对象。
然后实现会话管理,也就是bindrequest+unbindrequest。
然后实现ip白名单功能。
然后设计可以对接外部账号体系的接口。
上线后完美支撑业务需求。
我知道它有一些瑕疵,
比如openldap的表设计在字段中存了sql字句,而我用的EF无法发挥优势。
比如searchrequest指令处理里面没有实现成员组的支持。
比如bindrequest指令处理,同步账号又存储到ldap数据库的操作没有多少意义。
于是在今年底,我又花了大概一周时间,重构了一次:
干掉之前的ldap数据库临时存储账号的功能,替换为直接对接账号体系接口。
searchrequest指令处理时的查询缓存优化。
新增支持账号组。
开发调试协议是个繁琐的工作,因此我请来了apache目录服务客户端
对外的接口很简单,实现对应的接口定义就OK,其他的交给框架。
interface ILdapPersonStore { List<ILdapExternalObject> GetPersons(); } public interface ILdapExternalObject { Dictionary<string, string> Attributes { get; } /// <summary> /// 记录位置,唯一 /// </summary> /// <returns></returns> string GetDN(); /// <summary> /// 所属域 /// </summary> /// <returns></returns> string GetDC(); /// <summary> /// 通用名称 /// </summary> /// <returns></returns> string GetCN(); /// <summary> /// 类别 /// </summary> /// <returns></returns> string GetObjectClass(); } public interface ILdapPerson : ILdapExternalObject { /// <summary> /// 所属组织单元 /// </summary> /// <returns></returns> string GetOU(); /// <summary> /// 用户ID /// </summary> /// <returns></returns> string GetUID(); /// <summary> /// /// </summary> /// <returns></returns> string GetMemberOf(); /// <summary> /// UUID格式的唯一标识 /// </summary> /// <returns></returns> string GetEntryUUID(); /// <summary> /// 姓名 /// </summary> /// <returns></returns> string GetName(); /// <summary> /// 是否有下级 /// </summary> /// <returns></returns> bool GetHasSubordinates(); ILdapExternalObject groupOfUniqueNames { get; } }
轮子造好就等卖钱了