第三方包:go-ldap
方法文档:go-ldap docs
实现方法:
- 使用管理员账户密码进行Bind
- 根据要验证的用户名查找DN
- 使用要验证的用户DN和密码进行第二次Bind
核心代码:userAuth.go
package ldap
import (
"crypto/tls"
"fmt"
"github.com/go-ldap/ldap/v3"
"gopkg.in/ini.v1"
)
func UserAuthentication(user, pass string) error {
filePath := "./config/config.ini"
cfg, err := ini.Load(filePath)
if err != nil {
fmt.Printf("Fail to read file: %v\n", err)
return err
}
username = cfg.Section("AdServer").Key("Username").String()
password = cfg.Section("AdServer").Key("Password").String()
ldapUrl = cfg.Section("AdServer").Key("LdapUrl").String()
DN = cfg.Section("OrganizationalUnit").Key("BaseDN").String()
// tls 认证
tlsConfig := &tls.Config{InsecureSkipVerify: true}
l, err := ldap.DialTLS("tcp", ldapUrl, tlsConfig)
if err != nil {
return err
}
defer l.Close()
// 用户 bind,这个要bind一个具有域控管理的账号
err = l.Bind(username, password)
if err != nil {
return err
}
// 1. 先对用户进行搜索,是否在ldap中
filter := fmt.Sprintf("(&(objectClass=person)(sAMAccountName=%s))", user)
searchRequest := ldap.NewSearchRequest(
DN,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
//fmt.Sprintf("(&(objectClass=organizationalUnit))"),
filter,
[]string{"cn"},
nil,
)
sr, err := l.Search(searchRequest)
if err != nil {
return err
}
// 2. 进行二次bind,验证用户pass是否正确
userDN := sr.Entries[0].DN
err = l.Bind(userDN, pass)
if err != nil {
return err
}
return nil
}
config.ini
[AdServer]
Username = rsq
Password = 123456
LdapUrl = 192.168.1.1:636
[OrganizationalUnit]
BaseDN = DC=rsq,DC=local