2017-02-08 09:56
浏览 84

带有LDAP的golang webapp

I try to build web application using Active Directory authentication. I also need to get email address of a user. I have a function that can get email address. Where and how should I use the function to get email in mainHandler()?


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)


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)
        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", "", 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
    sr, err := conn.Search(searchRequest)
    if err != nil {
        return "", err
    email := sr.Entries[0].GetAttributeValue("mail")
    return strings.ToLower(email), nil
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • duanqu9279
    duanqu9279 2017-02-08 15:13

    The way your functions and handlers are wired, I do not see a whole lot of "clean" options to pass state back from BasicAuth() to the mainHandler() per request.

    If you are open to the idea of changing the way you setup your handlers, here is a skeleton structure which you can expand to fit your needs:

    package main
    import (
    type User struct {
        Name     string
        Password string
    func main() {
        mux := http.NewServeMux()
        mux.Handle("/", &User{})
        s := &http.Server{Addr: "localhost:8080", Handler: mux}
    func (u *User) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        //Pull out the username and 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"

    The User struct implements the ServeHTTP function, effectively implementing the http.Handler interface which opens up the option of adding it to a multiplexer which in turn helps maintain the username and password per request. Although the methods receive a pointer type you could change it to better suit your needs.

    点赞 评论