Honestamente, hay muchos métodos y técnicas de autenticación que puede montar en su aplicación y que dependen de la lógica y los requisitos comerciales de las aplicaciones.
Por ejemplo, Oauth2, LDAP, autenticación local, etc.
Mi respuesta asume que está buscando autenticación local, lo que significa que administra las identidades del usuario en su aplicación. El servidor debe exponer un conjunto de API externas que permiten a los usuarios y administradores Administrar las cuentas y cómo desean identificarse en el Servidor para lograr una comunicación confiable. terminarás creando una tabla DB que contiene la información del usuario. donde la contraseña se codifica por motivos de seguridad Consulte Cómo almacenar la contraseña en la base de datos
supongamos los requisitos de la aplicación para autenticar a los usuarios según uno de los siguientes métodos:
Autenticación básica (nombre de usuario, contraseña):
este método de autenticación depende de las credenciales de usuario establecidas en el encabezado de autorización codificado en base64 y definido en rfc7617 , básicamente cuando la aplicación recibe al usuario solicita que decodifique la autorización y vuelva a codificar la contraseña para compararla dentro de DB hash si coincide, el usuario autenticado devuelve el código de estado 401 al usuario.
autenticación basada en certificados:
este método de autenticación depende de un certificado digital para identificar a un usuario, y se conoce como autenticación x509, por lo que cuando la aplicación recibe las solicitudes del usuario, lee el certificado del cliente y verifica que coincida con el certificado raíz de CA proporcionado a la aplicación.
token de portador:
este método de autenticación depende de tokens de acceso de corta duración. El token de portador es una cadena críptica, generalmente generada por el servidor en respuesta a una solicitud de inicio de sesión. entonces, cuando la aplicación recibe las solicitudes del usuario, lee la autorización y valida el token para autenticar al usuario.
Sin embargo, recomendaría go-guardian
para la biblioteca de autenticación, que lo hace a través de un conjunto extensible de métodos de autenticación conocidos como estrategias. Básicamente, Go-Guardian no monta rutas ni asume ningún esquema de base de datos en particular, lo que maximiza la flexibilidad y permite que el desarrollador tome decisiones.
Configurar un autenticador de guardián es sencillo.
Aquí el ejemplo completo de los métodos anteriores.
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
curl -k https://127.0.0.1:8080/resource -H "Authorization: Bearer 90d64460d14870c08c81352a05dedd3465940a7"
Resource!!
- Autenticar con una credencial de usuario:
curl -k https://127.0.0.1:8080/resource -u stackoverflow:stackoverflow
Resource!!
- Autenticar con un certificado de usuario:
curl --cert client.pem --key client-key.pem --cacert ca.pem https://127.0.0.1:8080/resource
Resource!!
Puede habilitar varios métodos de autenticación a la vez. Por lo general, debe usar al menos dos métodos