英文:
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) string
的Secret
参数。
我该如何正确实现数据库查询并返回用于比较的密码?
英文:
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 "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()
}
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("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 ""
}
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("example.com", 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() {
secretdb = SecretDb{db}
...
auth.NewBasicAuthenticator("example.com", secretdb.Secret)
...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论