Skip to content

Instantly share code, notes, and snippets.

@LouisHrg
Last active September 27, 2019 13:47
Show Gist options
  • Select an option

  • Save LouisHrg/336c22cd13b8638f8d747a3d53def761 to your computer and use it in GitHub Desktop.

Select an option

Save LouisHrg/336c22cd13b8638f8d747a3d53def761 to your computer and use it in GitHub Desktop.
Middleware the works (REALLY) with gin
package middleware
import (
"net/http"
"errors"
"time"
"strings"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
)
type UnsignedResponse struct {
Message interface{} `json:"message"`
}
type SignedResponse struct {
Token string `json:"token"`
Message string `json:"message"`
}
func index(c *gin.Context) {
c.JSON(200, gin.H{"msg": "index"})
}
// LoginHandler : The login handler, set it for a /login route for example
func LoginHandler(c *gin.Context) {
type login struct {
Username string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
}
loginParams := login{}
c.ShouldBindJSON(&loginParams)
if loginParams.Username == "[email protected]" && loginParams.Password == "test" {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"user": loginParams.Username,
"nbf": time.Date(2018, 01, 01, 12, 0, 0, 0, time.UTC).Unix(),
})
tokenStr, err := token.SignedString([]byte("supersaucysecret"))
if err != nil {
c.JSON(http.StatusInternalServerError, UnsignedResponse{
Message: err.Error(),
})
return
}
c.JSON(http.StatusOK, SignedResponse{
Token: tokenStr,
Message: "logged in",
})
return
}
c.JSON(http.StatusBadRequest, UnsignedResponse{
Message: "bad username",
})
}
func extractBearerToken(header string) (string, error) {
if header == "" {
return "", errors.New("bad header value given")
}
jwtToken := strings.Split(header, " ")
if len(jwtToken) != 2 {
return "", errors.New("incorrectly formatted authorization header")
}
return jwtToken[1], nil
}
func parseToken(jwtToken string) (*jwt.Token, error) {
token, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) {
if _, OK := token.Method.(*jwt.SigningMethodHMAC); !OK {
return nil, errors.New("bad signed method received")
}
return []byte("supersaucysecret"), nil
})
if err != nil {
return nil, errors.New("bad jwt token")
}
return token, nil
}
// JwtTokenCheck : the middleware, register it for a group of routes
func JwtTokenCheck(c *gin.Context) {
jwtToken, err := extractBearerToken(c.GetHeader("Authorization"))
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, UnsignedResponse{
Message: err.Error(),
})
return
}
token, err := parseToken(jwtToken)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, UnsignedResponse{
Message: "bad jwt token",
})
return
}
_, OK := token.Claims.(jwt.MapClaims)
if !OK {
c.AbortWithStatusJSON(http.StatusInternalServerError, UnsignedResponse{
Message: "unable to parse claims",
})
return
}
c.Next()
}
func privateACLCheck(c *gin.Context) {
jwtToken, err := extractBearerToken(c.GetHeader("Authorization"))
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, UnsignedResponse{
Message: err.Error(),
})
return
}
token, err := parseToken(jwtToken)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, UnsignedResponse{
Message: "bad jwt token",
})
return
}
claims, OK := token.Claims.(jwt.MapClaims)
if !OK {
c.AbortWithStatusJSON(http.StatusInternalServerError, UnsignedResponse{
Message: "unable to parse claims",
})
return
}
claimedUID, OK := claims["user"].(string)
if !OK {
c.AbortWithStatusJSON(http.StatusBadRequest, UnsignedResponse{
Message: "no user property in claims",
})
return
}
uid := c.Param("uid")
if claimedUID != uid {
c.AbortWithStatusJSON(http.StatusBadRequest, UnsignedResponse{
Message: "token uid does not match resource uid",
})
return
}
c.Next()
}
@odrik
Copy link

odrik commented Sep 27, 2019

ok

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment