使用martini-go和go-http-auth查询数据库以进行基本身份验证。

huangapple go评论84阅读模式
英文:

Querying the database for basic auth using go-http-auth with martini-go

问题

我正在尝试在martini-go中使用go-http-auth。在这里给出的示例中 - https://github.com/abbot/go-http-auth

package main

import (
        auth "github.com/abbot/go-http-auth"
        "fmt"
        "net/http"
)

func Secret(user, realm string) string {
        if user == "john" {
                // password is "hello"
                return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
        }
        return ""
}

func handle(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
        fmt.Fprintf(w, "<html><body><h1>Hello, %s!</h1></body></html>", r.Username)
}


func main() {
    db, err := sql.Open("postgres", "postgres://blabla:blabla@localhost/my_db")
    authenticator := auth.NewBasicAuthenticator("example.com", Secret)
    m := martini.Classic()
    m.Map(db)
    m.Get("/users", authenticator.Wrap(MyUserHandler))
    m.Run()

}

Secret函数使用了一个硬编码的用户"john"。

当我执行以下命令时,认证成功:

curl --user john:hello localhost:3000/users

显然,这是一个使用硬编码的用户名和密码的简单示例。

现在,我将Secret函数更改为以下内容:

func Secret(user, realm string) string {

    fmt.Println("Executing Secret")

    var db *sql.DB

    var (
        username string
        password string
    )

    err := db.QueryRow("select username, password from users where username = ?", user).Scan(&username, &password)

    if err == sql.ErrNoRows {
        return ""
    }

    if err != nil {
        log.Fatal(err)
    }
    return ""
}

但是它会出现PANIC: runtime error: invalid memory address or nil pointer dereference.的错误。这显然是因为我试图在Secret函数中实例化var db *sql.DB。我也不能将db *sql.DB传递给Secret函数,因为auth.NewBasicAuthenticator期望一个符合type func (string, string) stringSecret参数。

我该如何正确实现数据库查询并返回用于比较的密码?

英文:

I am attempting to use go-http-auth with martini-go. In the example given here - https://github.com/abbot/go-http-auth

package main

import (
        auth &quot;github.com/abbot/go-http-auth&quot;
        &quot;fmt&quot;
        &quot;net/http&quot;
)

func Secret(user, realm string) string {
        if user == &quot;john&quot; {
                // password is &quot;hello&quot;
                return &quot;$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1&quot;
        }
        return &quot;&quot;
}

func handle(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
        fmt.Fprintf(w, &quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;Hello, %s!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;, r.Username)
}


func main() {
    db, err := sql.Open(&quot;postgres&quot;, &quot;postgres://blabla:blabla@localhost/my_db&quot;)
    authenticator := auth.NewBasicAuthenticator(&quot;example.com&quot;, Secret)
    m := martini.Classic()
    m.Map(db)
    m.Get(&quot;/users&quot;, authenticator.Wrap(MyUserHandler))
    m.Run()

}

The Secret function is using a hardcoded user "john".

The authentication is successful when I execute

curl --user john:hello localhost:3000/users

Obviously, this is a trivial example with hardcoded username and password.

I am now changing the Secret function to this

func Secret(user, realm string) string {

    fmt.Println(&quot;Executing Secret&quot;)

    var db *sql.DB

    var (
        username string
        password string
    )

    err := db.QueryRow(&quot;select username, password from users where username = ?&quot;, user).Scan(&amp;username, &amp;password)

    if err == sql.ErrNoRows {
        return &quot;&quot;
    }

    if err != nil {
        log.Fatal(err)
    }
    //if user == &quot;john&quot; {
        //// password is &quot;hello&quot;
        //return &quot;$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1&quot;
    //}
    //return &quot;&quot;
    return &quot;&quot;

}

But it fails with PANIC: runtime error: invalid memory address or nil pointer dereference. Which is obviously because I am attempting to instantiate var db *sql.DB in the Secret function. I cannot pass db *sql.DB into the Secret function either because auth.BasicNewAuthentication is expecting a Secret argument that conforms to type func (string, string) string.

How can I implement my database query correctly and return the password for comparison?

答案1

得分: 2

你可以使用一个简单的闭包将对数据库的引用传递给认证函数:

authenticator := auth.NewBasicAuthenticator("example.com", func(user, realm string) string {
    return Secret(db, user, realm)
})

然后,将你的 Secret 函数修改为接受数据库作为第一个参数:

func Secret(db *sql.DB, user, realm string) string {
    // 在这里进行数据库查询...
}
英文:

You can use a simple closure to pass in a reference to your DB to the authenticator function:

authenticator := auth.NewBasicAuthenticator(&quot;example.com&quot;, func(user, realm string) string {
    return Secret(db, user, realm)
})

…and then change your Secret to accept the database as the first argument:

func Secret(db *sql.DB, user, realm string) string {
    // do your db lookup here…
}

答案2

得分: 2

替代 Attila 的方法。你可以定义一个结构体,为其定义 Secret() 处理程序,并将只引用的函数(Go 会保留对 "owner" 的引用)传递给 authhandler

type SecretDb struct {
  db *DB
}

func (db *SecretDb) Secret(user, realm string) string {
 // 在这里使用 db.db
}


func main() {
   secretdb := SecretDb{db}
   ...
   auth.NewBasicAuthenticator("example.com", secretdb.Secret)
   ...
}
英文:

Alternative approach to Attilas answer. You can define a struct, define the Secret() handler on it and pass only the referenced function (go keeps the reference to the "owner") into the authhandler.

type SecretDb struct {
  db *DB
}
func (db *SecretDb) Secret(user, realm string) string {
 // .. use db.db here
}


func main()&#160;{
   secretdb = SecretDb{db}
   ...
   auth.NewBasicAuthenticator(&quot;example.com&quot;, secretdb.Secret)
   ...
}

huangapple
  • 本文由 发表于 2014年4月11日 15:50:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/23006639.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定