99 lines
3.0 KiB
Go
99 lines
3.0 KiB
Go
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
|
|
)
|
|
|
|
// JwtAuthMiddlewareV2 is responsible for protecting routes. Anything that may go wrong
|
|
// will be returned via JSON with a 'message' field and a 401 error code. When this
|
|
// middleware is successful, it will set the 'userId' and 'userEmail' fields and pass
|
|
// to the next function in the chain.
|
|
//
|
|
// Functions that are called after this can assume that those values defined are always
|
|
// set.
|
|
func JwtAuthMiddlewareV2(jwtSecretKey []byte) gin.HandlerFunc {
|
|
return func(ctx *gin.Context) {
|
|
tokenString, err := ctx.Cookie("jwt_token")
|
|
if err != nil {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{
|
|
"status": http.StatusUnauthorized,
|
|
"message": fmt.Sprintf("[UNAUTHORIZED] Failed to get token from cookie. %s", err.Error()),
|
|
})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
claims := &domain.JwtClaims{}
|
|
|
|
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
|
}
|
|
return jwtSecretKey, nil
|
|
})
|
|
|
|
// Error occurred when parsing
|
|
if err != nil {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{
|
|
"status": http.StatusUnauthorized,
|
|
"message": fmt.Sprintf("[UNAUTHORIZED] Error parsing cooking. %s", err.Error()),
|
|
})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
// Token is invalid
|
|
if !token.Valid {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{
|
|
"status": http.StatusUnauthorized,
|
|
"message": "[UNAUTHORIZED] Token is invalid.",
|
|
})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
// Found: Set the values
|
|
ctx.Set("userId", claims.UserId)
|
|
ctx.Set("userEmail", claims.Email)
|
|
ctx.Next()
|
|
}
|
|
}
|
|
|
|
// JwtOptionalAuthMiddlewareV2 is responsible for collecting user data for routes where
|
|
// authentication is optional. Meaning: if the use is not logged in, this function does
|
|
// not fail or return, it simply does nothing. But if the user is logged in, then the
|
|
// 'userId' and 'userEmail' context values are set.
|
|
//
|
|
// e.g., `userIdAny, exists := ctx.Get("userId")`
|
|
func JwtOptionalAuthMiddlewareV2(jwtSecretKey []byte) gin.HandlerFunc {
|
|
return func(ctx *gin.Context) {
|
|
tokenString, err := ctx.Cookie("jwt_token")
|
|
if err != nil || tokenString == "" {
|
|
// No cookie found: not authenticated, but allow access
|
|
ctx.Next()
|
|
return
|
|
}
|
|
|
|
claims := &domain.JwtClaims{}
|
|
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
|
}
|
|
return jwtSecretKey, nil
|
|
})
|
|
|
|
if err == nil && token.Valid {
|
|
// Set user info in context if token is valid
|
|
ctx.Set("userId", claims.UserId)
|
|
ctx.Set("userEmail", claims.Email)
|
|
}
|
|
// Otherwise, just continue (user is unauthenticated)
|
|
ctx.Next()
|
|
}
|
|
}
|