我尝试使用Active Directory身份验证构建Web应用程序。我还需要获取用户的电子邮件地址。我有一个可以获取电子邮件地址的功能。 我应该在哪里以及如何使用该函数在mainHandler()中获取电子邮件?
main.go
func main() {
http.HandleFunc("/", auth.BasicAuth(mainHandler))
http.ListenAndServe(":8080", nil)
}
func mainHandler(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("templates/main.html")
if err == nil {
tmpl.Execute(w, nil)
}
}
auth.go
type Handler func(w http.ResponseWriter, r *http.Request)
// BasicAuth - handler wrapper for authentication
func BasicAuth(pass Handler) Handler {
return func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
err := ValidateAD(username, password)
if err != nil || !ok {
realm := "Please enter your corporate key and password"
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
// w.WriteHeader(401)
http.Error(w, "authorization failed", http.StatusUnauthorized)
return
}
pass(w, r)
}
}
var ErrEmptyUserOrPass = errors.New("Username or password cannot be empty")
var conn *ldap.Conn
// ValidateAD validation based on Active Directory
func ValidateAD(user, passwd string) error {
if user == "" || passwd == "" {
return ErrEmptyUserOrPass
}
tlsConfig := &tls.Config{InsecureSkipVerify: true}
var err error
conn, err = ldap.DialTLS("tcp", "ad.something.com:636", tlsConfig)
if err != nil {
return err
}
defer conn.Close()
domainPrefix := "ad\\"
err = conn.Bind(domainPrefix+user, passwd)
if err != nil {
return err
}
return nil
}
// GetLDAPEmail returns email address for given username and password
func GetLDAPEmail(user, password string) (string, error) {
if err := ValidateAD(user, password); err != nil {
return "", err
}
searchBase := "CN=" + user + ",OU=OU1,OU=OU2,OU=OU3,DC=ad,DC=something,DC=com"
searchFilter := "(&(samAccountName=" + user + "))"
searchRequest := ldap.NewSearchRequest(
searchBase, // The base dn to search
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
searchFilter, // The filter to apply
[]string{"mail"}, // A list attributes to retrieve
nil,
)
sr, err := conn.Search(searchRequest)
if err != nil {
return "", err
}
email := sr.Entries[0].GetAttributeValue("mail")
return strings.ToLower(email), nil
}
答案 0 :(得分:1)
您的函数和处理程序的连接方式,我没有看到很多“干净”的选项,可以根据请求将状态从BasicAuth()
传递回mainHandler()
。
如果您愿意改变设置处理程序的方式,这里有一个骨架结构,您可以扩展以满足您的需求:
package main
import (
"fmt"
"log"
"net/http"
)
type User struct {
Name string
Password string
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", &User{})
s := &http.Server{Addr: "localhost:8080", Handler: mux}
log.Fatal(s.ListenAndServe())
}
func (u *User) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//Pull out the username and password
u.BasicAuth()
fmt.Println(u.Name)
fmt.Println(u.Password)
//The rest of your main handler
}
func (u *User) BasicAuth() {
//This is to demonstrate the ability to pass state
//Edit this to fit your needs
u.Name = "user"
u.Password = "pass"
}
User
结构实现了ServeHTTP功能,有效地实现了http.Handler
interface,这开启了将其添加到多路复用器的选项,而多路复用器又有助于维护每个请求的用户名和密码。虽然方法接收指针类型,但您可以更改它以更好地满足您的需求。