Abfragen der Datenbank nach Basisauthentifizierung mithilfe von go-http-auth mit martini-go
-
21-12-2019 - |
Frage
Ich versuche, go-http-auth mit martini-go zu verwenden.In dem hier gegebenen Beispiel - 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()
}
Die Secret-Funktion verwendet einen fest codierten Benutzer „john“.
Die Authentifizierung ist erfolgreich, wenn ich sie ausführe
curl --user john:hello localhost:3000/users
Dies ist offensichtlich ein triviales Beispiel mit fest codiertem Benutzernamen und Passwort.
Ich ändere jetzt das Secret
Funktion dazu
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 ""
}
Aber es scheitert mit PANIC: runtime error: invalid memory address or nil pointer dereference.
Das liegt offensichtlich daran, dass ich versuche zu instanziieren var db *sql.DB
im Secret
Funktion.Ich kann nicht bestehen db *sql.DB
in die Secret
Funktion entweder weil auth.BasicNewAuthentication
erwartet einen Secret
Argument, das entspricht type func (string, string) string
.
Wie kann ich meine Datenbankabfrage korrekt umsetzen und das Passwort zum Vergleich zurückgeben?
Lösung
Sie können einen einfachen Abschluss verwenden, um einen Verweis auf Ihre Datenbank an die Authentifikatorfunktion zu übergeben:
authenticator := auth.NewBasicAuthenticator("example.com", func(user, realm string) string {
return Secret(db, user, realm)
})
…und dann ändern Sie Ihre Secret
um die Datenbank als erstes Argument zu akzeptieren:
func Secret(db *sql.DB, user, realm string) string {
// do your db lookup here…
}
Andere Tipps
Alternativer Ansatz zur Antwort von Attilas.Sie können eine Struktur definieren, die definieren Secret()
Handler darauf und übergeben Sie nur die referenzierte Funktion (go behält den Verweis auf den „Eigentümer“) an den 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)
...
}