Onestamente, ci sono molti metodi e tecniche di autenticazione che puoi montare nella tua applicazione e che dipendono dalla logica e dai requisiti aziendali delle applicazioni.
Ad esempio Oauth2, LDAP, autenticazione locale, ecc. La
mia risposta presuppone che tu stia cercando l'autenticazione locale, il che significa che gestisci le identità dell'utente nella tua applicazione. Il server deve esporre una serie di API esterne che consentano agli utenti e agli amministratori di gestire gli account e il modo in cui desiderano identificarsi sul server per ottenere comunicazioni affidabili. finirai per creare una tabella DB contenente le informazioni dell'utente. dove la password è sottoposta a hash per motivi di sicurezza Vedere Come archiviare la password nel database
assumiamo i requisiti delle app per autenticare gli utenti in base a uno dei seguenti metodi:
autenticazione di base (nome utente, password):
questo metodo di autenticazione dipende dalle serie di credenziali dell'utente nell'intestazione dell'autorizzazione codificate in base64 e definite in rfc7617 , fondamentalmente quando l'app riceve l'utente richiede la decodifica dell'autorizzazione e ricodifica la password per confrontarla all'interno del DB hash se corrisponde all'utente autenticato, altrimenti restituisce il codice di stato 401 all'utente.
autenticazione basata su certificato:
questo metodo di autenticazione dipende da un certificato digitale per identificare un utente ed è noto come x509 auth, quindi quando l'app riceve le richieste dell'utente, legge il certificato del client e verifica che corrisponda al certificato radice CA fornito all'APP.
token bearer:
questo metodo di autenticazione dipende da token di accesso di breve durata, il token bearer è una stringa criptica, generalmente generata dal server in risposta a una richiesta di accesso. quindi quando l'app riceve le richieste dell'utente, legge l'autorizzazione e convalida il token per autenticare l'utente.
Tuttavia, consiglierei go-guardian
per la libreria di autenticazione che fa attraverso una serie estensibile di metodi di autenticazione noti come strategie. fondamentalmente Go-Guardian non monta route o assume alcun particolare schema di database, il che massimizza la flessibilità e consente alle decisioni di essere prese dallo sviluppatore.
La configurazione di un autenticatore del guardiano è semplice.
Ecco l'esempio completo dei metodi di cui sopra.
package main
import (
"context"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
"net/http"
"sync"
"github.com/golang/groupcache/lru"
"github.com/gorilla/mux"
"github.com/shaj13/go-guardian/auth"
"github.com/shaj13/go-guardian/auth/strategies/basic"
"github.com/shaj13/go-guardian/auth/strategies/bearer"
gx509 "github.com/shaj13/go-guardian/auth/strategies/x509"
"github.com/shaj13/go-guardian/store"
)
var authenticator auth.Authenticator
var cache store.Cache
func middleware(next http.Handler) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("Executing Auth Middleware")
user, err := authenticator.Authenticate(r)
if err != nil {
code := http.StatusUnauthorized
http.Error(w, http.StatusText(code), code)
return
}
log.Printf("User %s Authenticated\n", user.UserName())
next.ServeHTTP(w, r)
})
}
func Resource(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Resource!!\n"))
}
func Login(w http.ResponseWriter, r *http.Request) {
token := "90d64460d14870c08c81352a05dedd3465940a7"
user := auth.NewDefaultUser("admin", "1", nil, nil)
cache.Store(token, user, r)
body := fmt.Sprintf("token: %s \n", token)
w.Write([]byte(body))
}
func main() {
opts := x509.VerifyOptions{}
opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
opts.Roots = x509.NewCertPool()
// Read Root Ca Certificate
opts.Roots.AddCert(readCertificate("<root-ca>"))
cache = &store.LRU{
lru.New(100),
&sync.Mutex{},
}
// create strategies
x509Strategy := gx509.New(opts)
basicStrategy := basic.New(validateUser, cache)
tokenStrategy := bearer.New(bearer.NoOpAuthenticate, cache)
authenticator = auth.New()
authenticator.EnableStrategy(gx509.StrategyKey, x509Strategy)
authenticator.EnableStrategy(basic.StrategyKey, basicStrategy)
authenticator.EnableStrategy(bearer.CachedStrategyKey, tokenStrategy)
r := mux.NewRouter()
r.HandleFunc("/resource", middleware(http.HandlerFunc(Resource)))
r.HandleFunc("/login", middleware(http.HandlerFunc(Login)))
log.Fatal(http.ListenAndServeTLS(":8080", "<server-cert>", "<server-key>", r))
}
func validateUser(ctx context.Context, r *http.Request, userName, password string) (auth.Info, error) {
// here connect to db or any other service to fetch user and validate it.
if userName == "stackoverflow" && password == "stackoverflow" {
return auth.NewDefaultUser("stackoverflow", "10", nil, nil), nil
}
return nil, fmt.Errorf("Invalid credentials")
}
func readCertificate(file string) *x509.Certificate {
data, err := ioutil.ReadFile(file)
if err != nil {
log.Fatalf("error reading %s: %v", file, err)
}
p, _ := pem.Decode(data)
cert, err := x509.ParseCertificate(p.Bytes)
if err != nil {
log.Fatalf("error parseing certificate %s: %v", file, err)
}
return cert
}
Uso:
curl -k https://127.0.0.1:8080/login -u stackoverflow:stackoverflow
token: 90d64460d14870c08c81352a05dedd3465940a7
- Autenticare con un token:
curl -k https://127.0.0.1:8080/resource -H "Authorization: Bearer 90d64460d14870c08c81352a05dedd3465940a7"
Resource!!
- Autenticare con le credenziali dell'utente:
curl -k https://127.0.0.1:8080/resource -u stackoverflow:stackoverflow
Resource!!
- Autenticare con un certificato utente:
curl --cert client.pem --key client-key.pem --cacert ca.pem https://127.0.0.1:8080/resource
Resource!!
È possibile abilitare più metodi di autenticazione contemporaneamente. Di solito dovresti usare almeno due metodi