goalng 如何獲取 ldap 服務(wù)器的數(shù)據(jù)?
我們工作在和其他組織配合時,我們可能不是作為服務(wù)器搭建的一方,而是屬于客戶端的一方,需要去獲取服務(wù)器的組織結(jié)構(gòu),按照某些條件去獲取服務(wù)器的數(shù)據(jù),也可以是同步組織結(jié)構(gòu)
雖然說 golang 的數(shù)據(jù)結(jié)構(gòu)沒有 c++ 那么豐富,不過對于這個 ldap 還是有相應(yīng)的庫來進(jìn)行處理的
官方文檔地址: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 服務(wù)器上的組織結(jié)構(gòu)
這是我們簡單搭建的 ldap 服務(wù)器,可以使用 LDAP Admin 可視化管理工具來查看具體的頁面效果
我們把這個庫下載下來后,我們的編碼思路如下:
填寫 ldap 服務(wù)器地址以及填寫相應(yīng)的管理員信息,與 ldap 服務(wù)器建立連接
編寫查詢請求,并開始向 ldap 服務(wù)器進(jìn)行查詢
將查詢結(jié)構(gòu),按照 ldap v3 庫提供的方式 打印出效果來
連接 服務(wù)器
我們可以使用 func DialURL(addr string, opts ...DialOpt) (*Conn, error)
函數(shù)來與 ldap 服務(wù)器建立連接
ml,?err?:=?ldap.DialURL("ldap://xxxx")
?if?err?!=?nil?{
??log.Fatal(err)
?}
?defer?ml.Close()
我們填入的地址中,可以不用輸入端口號,庫函數(shù)已經(jīng)有給我們做好處理,我們可以來看看源碼
DialURL
函數(shù)用于連接 ldap 服務(wù)器,連接成功會給我們返回一個新的連接
我們可以繼續(xù)看一下這個函數(shù)調(diào)用 ?c, err := dc.dial(u)
golang 的庫會根據(jù)我們填寫的地址是 ldap 還是 ldaps 來判斷是做加密傳輸還是不加密傳輸,與之對應(yīng)的就是訪問不加密的用 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?!!")
來看看實(shí)際的 SimpleBindRequest
數(shù)據(jù)結(jié)構(gòu)
//?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
是否允許空密碼,若是空密碼,一般是綁定一個未授權(quán)的用戶
編寫查詢請求,并開始查詢 ldap 服務(wù)器
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))
編寫查詢請求,也就是簡單的給我們的結(jié)構(gòu)體進(jìn)行一個負(fù)值操作,填寫好對相應(yīng)的參數(shù),即可開始查詢,一起來看看這個結(jié)構(gòu)體NewSearchRequest
基本上就是填寫相應(yīng)的域信息
BaseDN , 一個域唯一的標(biāo)識
scope 范圍的選擇,我們默認(rèn)選擇
ScopeWholeSubtree
,查詢所有的子樹DerefAliases , SizeLimit,TimeLimit,TypesOnly 填寫默認(rèn)值即可
Filter , 查詢需要的過濾條件,可以按照我們的實(shí)際情況寫條件,就像寫查詢數(shù)據(jù)庫的條件一樣,這里不能為空,否則會程序崩潰
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 , 需要返回的屬性有哪些,是一個切片,如果我們默認(rèn)填空,則會返回所有屬性
查看對應(yīng)的 ?Search
函數(shù)源碼
代碼的大致邏輯是,doRequest
將數(shù)據(jù)組包向 ldap 服務(wù)器發(fā)送請求,請求成功之后,將響應(yīng)的數(shù)據(jù)按照 tag 不同的內(nèi)容進(jìn)行解析
最終返回一個 *SearchResult
查詢結(jié)果的指針
輸入查詢信息
for?_,?item?:=?range?searchResult.Entries?{
???item.Print()
???fmt.Printf("\n\n")
}
上圖源碼我們可以看到輸出查詢信息就是遍歷一下 searchResult.Entries
,我們可以來看看對應(yīng)的數(shù)據(jù)結(jié)構(gòu)
我們可以看到結(jié)果里面,有一個 Entries []*Entry
是一個切片,里面放了多個 *Entry
, ?在 ldap 服務(wù)器中, ?1 個 Entry 就代表一條唯一的記錄
Entry ?結(jié)構(gòu)體就是對應(yīng)的 DN,一條記錄唯一的辨別名 , 和他涉及的屬性
EntryAttribute 屬性結(jié)構(gòu)體中,我們可以看到 有 Name ,有 Values ,這里就是對應(yīng)我們之前說到的 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]
結(jié)果是輸出了 1 條信息,沒錯,因?yàn)槲覀兊?ou=people 只有 1條記錄,如果我們需要查詢整個 ldap服務(wù)器的所有數(shù)據(jù),則我們可以將上述代碼的 Filter 位置,修改成 objectClass=*
解釋上述結(jié)果:
DN 表示唯一的記錄,是辨別名的意思
objectClass 是一個類,這里對應(yīng)的是 organizationalUnit ,表示組織單元OU,可以理解為 組
ou: [People] 指的是這個 ou 對應(yīng)的名字是 People
歡迎點(diǎn)贊,關(guān)注,收藏
朋友們,你的支持和鼓勵,是我堅持分享,提高質(zhì)量的動力
好了,本次就到這里
技術(shù)是開放的,我們的心態(tài),更應(yīng)是開放的。擁抱變化,向陽而生,努力向前行。
我是阿兵云原生,歡迎點(diǎn)贊關(guān)注收藏,下次見~