Interrogation de la base de données pour l'authentification de base à l'aide de go-http-auth avec martini-go
-
21-12-2019 - |
Question
J'essaie d'utiliser go-http-auth avec martini-go.Dans l'exemple donné ici - 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()
}
La fonction Secret utilise un utilisateur "john" codé en dur.
L'authentification est réussie lorsque j'exécute
curl --user john:hello localhost:3000/users
Évidemment, il s’agit d’un exemple trivial avec un nom d’utilisateur et un mot de passe codés en dur.
Je change maintenant le Secret
fonction à cela
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 ""
}
Mais ça échoue avec PANIC: runtime error: invalid memory address or nil pointer dereference.
C'est évidemment parce que j'essaie d'instancier var db *sql.DB
dans le Secret
fonction.je ne peux pas passer db *sql.DB
dans le Secret
fonctionner soit parce que auth.BasicNewAuthentication
s'attend à un Secret
argument conforme à type func (string, string) string
.
Comment puis-je implémenter correctement ma requête de base de données et renvoyer le mot de passe pour comparaison ?
La solution
Vous pouvez utiliser une simple fermeture pour transmettre une référence à votre base de données à la fonction d'authentification :
authenticator := auth.NewBasicAuthenticator("example.com", func(user, realm string) string {
return Secret(db, user, realm)
})
…puis changez votre Secret
pour accepter la base de données comme premier argument :
func Secret(db *sql.DB, user, realm string) string {
// do your db lookup here…
}
Autres conseils
Approche alternative à la réponse d'Attilas.Vous pouvez définir une structure, définir le Secret()
gestionnaire dessus et transmettez uniquement la fonction référencée (go conserve la référence au "propriétaire") dans le 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)
...
}