Retrieve value from gin context

1.7k Views Asked by At

I have this code

package middleware

import (
    "net/http"

    "github.com/dgrijalva/jwt-go"
    "github.com/gin-gonic/gin"
    "github.com/irohitb/EmpAdmin/backend/domain"
)




type UserToken struct {
    jwt.StandardClaims
    User domain.UserToken
}


func SessionMiddleware(supabase_secret string) gin.HandlerFunc {
    return func(c *gin.Context) {
        userCookie, err := c.Cookie("user")
        if err != nil {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"success": false, "message": "Missing user cookie"})
            return
        }

        token, err := jwt.ParseWithClaims(userCookie, &UserToken{}, func(token *jwt.Token) (interface{}, error) {
            return []byte(supabase_secret), nil
        })
        if err != nil {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"success": false, "message": "Invalid user cookie"})
            return
        }

        claims, ok := token.Claims.(*UserToken)
        if !ok || !token.Valid {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"success": false, "message": "Invalid user token"})
            return
        }

        if !claims.User.IsAdmin {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"success": false, "message": "Only Admins can perform this action"})
            return
        }

        c.Set("user", claims)
        c.Next()
    }
}

Now, in my router, how can I get value set using c.Get("user")?

package services

import (
    "net/http"
    "strings"

    "github.com/gin-gonic/gin"
    "github.com/irohitb/EmpAdmin/backend/config"
    "github.com/irohitb/EmpAdmin/backend/domain"
    "github.com/supabase/postgrest-go"
)


func GetAllUsers(env *config.Env, db *postgrest.Client, group *gin.RouterGroup) {
    group.GET("/:services", func (router *gin.Context) {
        services := strings.Split(router.Param("service"), ",")
        user, exists := router.Get("user")
        if !exists {
            router.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "user information not found in context"})
            return
        }

    
        workspaceId, exists := user.(middleware.UserToken).WorkspaceID
         if !exists {
            router.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "workspace_id not found in user information"})
            return
        }
        
    })
}

This line here is throwing the following error:

routes/services/users.go:16:3: services declared and not used
routes/services/users.go:24:54: user.(middleware.UserToken).WorkspaceID undefined (type middleware.UserToken has no field or method WorkspaceID)
1

There are 1 best solutions below

0
Zeke Lu On

This is a compile time error instead of a runtime error. It's misleading to say that "This line here is throwing following error".

services declared and not used

This is an implementation restriction in Go, A compiler may make it illegal to declare a variable inside a function body if the variable is never used (see the language spec). To fix this issue, either remove services or use it.

user.(middleware.UserToken).WorkspaceID undefined (type middleware.UserToken has no field or method WorkspaceID)

Let's correct some other issues first.

  1. There is a syntax error in the type assertion:

    workspaceId, exists := user.(middleware.UserToken).WorkspaceID
    

    should be written as:

    userToken, exists := user.(middleware.UserToken)
    if exists {
      workspaceId := userToken.WorkspaceID
    }
    
  2. According to claims, ok := token.Claims.(*UserToken), the claims has the type *UserToken instead of UserToken. So user.(middleware.UserToken) should be user.(*middleware.UserToken).

Now let's turn back to the error. That means the struct middleware.UserToken does not have the field WorkspaceID. Maybe it's a field of the struct domain.UserToken. Let's assume this is the case, then the overall fix should be:

userToken, ok := user.(*middleware.UserToken)
if !ok {
    router.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": `router.Get("user") is not a UserToken`})
    return
}
workspaceId := userToken.User.WorkspaceId
// use workspaceId below