咱们工作在和其余组织配合时,咱们可能不是作为服务器搭建的一方,而是属于客户端的一方,须要去获取服务器的组织构造,依照某些条件去获取服务器的数据,也能够是同步组织构造
尽管说 golang 的数据结构没有 c++ 那么丰盛,不过对于这个 ldap 还是有相应的库来进行解决的
官网文档地址:https://pkg.go.dev/gopkg.in/ldap.v3
咱们也能够下载 github 下面的这个库
go get github.com/go-ldap/ldap/v3
golang 对于 ldap 库最新的版本是 Version: v3.1.0
开始编码
咱们来写一个 demo,获取咱们上次搭建的 ldap 服务器上的组织构造
这是咱们简略搭建的 ldap 服务器,能够应用 LDAP Admin 可视化管理工具来查看具体的页面成果
咱们把这个库下载下来后,咱们的编码思路如下:
- 填写 ldap 服务器地址以及填写相应的管理员信息,与 ldap 服务器建设连贯
- 编写查问申请,并开始向 ldap 服务器进行查问
- 将查问构造,依照 ldap v3 库提供的形式 打印出成果来
连贯 服务器
咱们能够应用 func DialURL(addr string, opts ...DialOpt) (*Conn, error)
函数来与 ldap 服务器建设连贯
ml, err := ldap.DialURL("ldap://xxxx")
if err != nil {log.Fatal(err)
}
defer ml.Close()
咱们填入的地址中,能够不必输出端口号,库函数曾经有给咱们做好解决,咱们能够来看看源码
DialURL
函数用于连贯 ldap 服务器,连贯胜利会给咱们 返回一个新的连贯
咱们能够持续看一下这个函数调用 c, err := dc.dial(u)
golang 的库会依据咱们填写的地址是 ldap 还是 ldaps 来判断是做加密传输还是不加密传输 ,与之对应的就是拜访 不加密的用 389 端口 , 加密的就应用 636 端口
增加管理员绑定信息
咱们增加的 ldap 域信息为:dc=xiaomotong,dc=com
我的管理员是:cn=admin,dc=xiaomotong,dc=com
_, err = ml.SimpleBind(&ldap.SimpleBindRequest{
Username: "cn=admin,dc=xiaomotong,dc=com",
Password: "123123",
})
if err != nil {log.Fatalf("Failed to bind: %s\n", err)
}
fmt.Println("connect successfully !!")
来看看理论的 SimpleBindRequest
数据结构
// SimpleBindRequest represents a username/password bind operation
type SimpleBindRequest struct {
// Username is the name of the Directory object that the client wishes to bind as
Username string
// Password is the credentials to bind with
Password string
// Controls are optional controls to send with the bind request
Controls []Control
// AllowEmptyPassword sets whether the client allows binding with an empty password
// (normally used for unauthenticated bind).
AllowEmptyPassword bool
}
- Username
- Password
客户端须要绑定的域用户和明码
- Controls
须要绑定申请的控件
- AllowEmptyPassword
是否容许空明码,若是空明码,个别是绑定一个未受权的用户
编写查问申请,并开始查问 ldap 服务器
searchRequest := ldap.NewSearchRequest(
"dc=xiaomotong,dc=com",
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
0,
false,
"(ou=People)",
[]string{},
nil,
)
searchResult, err := ml.Search(searchRequest)
if err != nil {log.Println("can't search ", err.Error())
}
log.Printf("%d", len(searchResult.Entries))
编写查问申请,也就是简略的给咱们的构造体进行一个负值操作,填写好对相应的参数,即可开始查问,一起来看看这个构造体NewSearchRequest
基本上就是填写相应的域信息
- BaseDN,一个域惟一的标识
- scope 范畴的抉择,咱们默认抉择
ScopeWholeSubtree
,查问所有的子树 - DerefAliases,SizeLimit,TimeLimit,TypesOnly 填写默认值即可
- Filter,查问须要的过滤条件,能够依照咱们的理论状况写条件,就像写查询数据库的条件一样,这里不能为空,否则会程序解体
F:\codegitee\golang_study\later_learning\ldap_test>go run main.go
connect successfully !!
2021/11/06 21:07:59 can't search LDAP Result Code 201"Filter Compile Error": ldap: error parsing filter
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x4 pc=0xa33cef]
goroutine 1 [running]:
main.main()
F:/codegitee/golang_study/later_learning/ldap_test/main.go:40 +0x24f
exit status 2
- Attributes,须要返回的属性有哪些,是一个切片,如果咱们默认填空,则会返回所有属性
查看对应的 Search
函数源码
代码的大抵逻辑是,doRequest
将数据组包向 ldap 服务器发送申请,申请胜利之后,将响应的数据 依照 tag 不同的内容进行解析
最终返回一个 *SearchResult
查问后果的指针
输出查问信息
for _, item := range searchResult.Entries {item.Print()
fmt.Printf("\n\n")
}
上图源码咱们能够看到输入查问信息就是遍历一下 searchResult.Entries
,咱们能够来看看对应的数据结构
咱们能够看到后果外面,有一个 Entries []*Entry
是一个切片,外面放了多个 *Entry
, 在 ldap 服务器中,1 个 Entry 就代表一条惟一的记录
Entry 构造体就是对应的 DN,一条记录惟一的分别名,和他波及的属性
EntryAttribute 属性构造体中,咱们能够看到 有 Name,有 Values,这里就是对应咱们之前说到的 RDN,也就是一个键值对,多个键值对组成一个 DN
最终咱们来查看一下成果
>go run main.go
connect successfully !!
2021/11/06 21:20:58 1
DN: ou=People,dc=xiaomotong,dc=com
objectClass: [organizationalUnit]
ou: [People]
后果是输入了 1 条信息,没错,因为咱们的 ou=people 只有 1 条记录,如果咱们须要查问整个 ldap 服务器的所有数据,则咱们能够将上述代码的 Filter 地位,批改成 objectClass=*
解释上述后果:
- DN 示意惟一的记录,是分别名的意思
- objectClass 是一个类,这里对应的是 organizationalUnit,示意组织单元 OU,能够了解为 组
- ou: [People] 指的是这个 ou 对应的名字是 People
欢送点赞,关注,珍藏
敌人们,你的反对和激励,是我保持分享,提高质量的能源
好了,本次就到这里
技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。
我是 阿兵云原生,欢送点赞关注珍藏,下次见~