我正在尝试将 go-http-auth 与 martini-go 一起使用。在此处给出的示例中 - 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)
    }
    //if user == "john" {
        //// password is "hello"
        //return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
    //}
    //return ""
    return ""

}

但它失败了 PANIC: runtime error: invalid memory address or nil pointer dereference. 这显然是因为我正在尝试实例化 var db *sql.DB 在里面 Secret 功能。我无法通过 db *sql.DB 进入 Secret 函数要么因为 auth.BasicNewAuthentication 正在期待一个 Secret 符合的论点 type func (string, string) string.

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

有帮助吗?

解决方案

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

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 {
    // do your db lookup here…
}

其他提示

阿提拉斯答案的替代方法。您可以定义一个结构体,定义 Secret() 处理程序并仅将引用的函数(go 保留对“所有者”的引用)传递到 authhandler.

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


func main() {
   secretdb = SecretDb{db}
   ...
   auth.NewBasicAuthenticator("example.com", secretdb.Secret)
   ...
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top