No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

5D
4H
9M
16S

Implementando el middleware

16/26
Recursos

Aportes 7

Preguntas 1

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

La soluci贸n que hace casi al final de la clase, la de modificar el fichero auth.go y enviar una referencia al models.AppClaims, tambi茅n debe hacerse a la funci贸n de MeHandler

func MeHandler(s server.Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		tokenString := strings.TrimSpace(r.Header.Get("Authorization"))

		token, err := jwt.ParseWithClaims(tokenString, &models.AppClaims{}, func(token *jwt.Token) (interface{}, error) {
			return []byte(s.Config().JWTSecret), nil
		})
		if err != nil {
			http.Error(w, err.Error(), http.StatusUnauthorized)
			return
		}

		if claims, ok := token.Claims.(*models.AppClaims); ok && token.Valid {
			user, err := repository.GetUserById(r.Context(), claims.UserId)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(user)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

La interface de la librer铆a deber铆a contemplar este problema en forma de chequeo de tipos y, especificar, que se debe recibir una referencia estrictamente. De esta forma el compilador te avisar铆a sobre este error en lugar de recibirlo cuando pruebas la aplicaci贸n.

Para la abstracci贸n de c贸digo he creado una carpeta llamada helpers y en ella un fichero llamado jwtHelper.go, el cual contiene la siguiente funci贸n:

func GetJWTAuthorizationInfo(s server.Server, w http.ResponseWriter, r *http.Request) (*jwt.Token, error) {
	tokenString := strings.TrimSpace(r.Header.Get("Authorization"))
	token, err := jwt.ParseWithClaims(tokenString, models.AppClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(s.Config().JWTSecret), nil
	})

	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
	}

	return token, err
}

Los c贸digos que realizan la llamada la pueden utilizar tal que as铆:

		token, err := helpers.GetJWTAuthorizationInfo(s, w, r)

		if err != nil {
			return
		}

Les comparto una opci贸n para no repetir el c贸digo de verificaci贸n del token .
En el middleware, al verificar el token podemos obtener el UserId y lo guardamos en el contexto de ejecuci贸n; posteriormente en el handler podemos recuperarlo y traer la data del usuario.


middleware/auth.go

func CheckAuthMiddleware(s server.Server) func(h http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if !shouldCheckToken(r.URL.Host) {
				next.ServeHTTP(w, r)
				return
			}
			tokenString := strings.TrimSpace(r.Header.Get("Authorization"))
			token, err := jwt.ParseWithClaims(tokenString, &models.AppClaims{}, func(t *jwt.Token) (interface{}, error) {
				return []byte(s.Config().JWTSecret), nil
			})
			if err != nil {
				http.Error(w, err.Error(), http.StatusUnauthorized)
				return
			}

			claims, ok := token.Claims.(*models.AppClaims)
			if ok && token.Valid {
				log.Printf("User ID: %s", claims.UserId)
				ctx := context.WithValue(r.Context(), ContextUserID, claims.UserId)
				r = r.WithContext(ctx)
			}// 

			next.ServeHTTP(w, r)
		})
	}
}

handlers/user.go

func MeHandler(s server.Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		userID := r.Context().Value(middleware.ContextUserID)
		if userID == "" {
			http.Error(w, "Invalid credentials", http.StatusUnauthorized)
			return
		}

		user, err := repository.GetUserById(r.Context(), userID.(string))
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(user)
	}
}
func MeHandler(s server.Server) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		tokenString := strings.TrimSpace(r.Header.Get("Authorization"))
		token, err := jwt.ParseWithClaims(tokenString, &models.AppClaims{}, func(token *jwt.Token) (interface{}, error) {
			return []byte(s.Config().JWTSecret), nil
		})
		if err != nil {
			http.Error(w, err.Error(), http.StatusUnauthorized)
			return
		}
		if claims, ok := token.Claims.(*models.AppClaims); ok && token.Valid {
			user, err := repository.GetUserById(r.Context(), claims.UserId)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			json.NewEncoder(w).Encode(user)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

Ya para no duplicar el c贸digo del middleware de autorizaci贸n lo que hice fue extraer ah铆 mismo el userId del token e insertarlo en los headers.
Entonces cuando llega al MeHandler puedo extraer del los headers el userId.
No se si est茅 bien, me gustar铆a que alguien me diera su opini贸n
Este es el middleware

Este es el handler

Una posible soluci贸n para el reto que nos plantea Nestor es la siguiente:

func ParseToken(hauth string, claims jwt.Claims) (jwt.Token, error) {
	// hauth: Autohorization Header
	// claims: Any type that implemnts jwt.Claims. AppClaims Does b/c jwt.StandardClaims does.
	strim := strings.TrimSpace(hauth)
	token, err := jwt.ParseWithClaims(strim, claims, func(t *jwt.Token) (interface{}, error) {
		return []byte(database.BuildConfig().JWTSecret), nil
	})
	return *token, err
}

el database.BuildConfig est谩 apuntando al archivo de configuraci贸n, que a prop贸sito no estar铆a mal sacarlo de server.go y tenerlo en su propio archivo config.go., esto entre otras cosas ahorrar铆a tener que pasar el servidor como par谩metro en los los middlewares.