package auth import ( "fmt" "net/http" "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" ) const ( CtxRequestHeaderUserId = "user_id" ctxRequestHeaderAuthorization = "Authorization" ctxRequestCookieAuthorization = "ak" ctxRequestTokenExpired = "expired" ) func Auth(authKey string, session Session) gin.HandlerFunc { return func(ctx *gin.Context) { var tokenFromCookie, tokenFromHeader string tokenFromCookie, err := ctx.Cookie(ctxRequestCookieAuthorization) if err == http.ErrNoCookie { tokenFromHeader = ctx.Request.Header.Get(ctxRequestHeaderAuthorization) } if tokenFromHeader == "" { tokenFromHeader = "Bearer " + tokenFromCookie } if len(tokenFromHeader) < 8 { ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed"}) return } token, err := jwt.Parse(tokenFromHeader[7:], 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 []byte(authKey), nil }) if err != nil || !token.Valid { ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed"}) return } if !session.IsExistsJwtToken(token.Raw) { ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, token expired by server"}) return } if mapClaims, ok := token.Claims.(jwt.MapClaims); ok { if expired, ok := mapClaims[ctxRequestTokenExpired].(float64); ok { if expired == 0 && tokenFromCookie == "" { if session.DeleteJwtToken(token.Raw) { ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, token expired"}) } else { ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, delete server token failed"}) } return } if uid, ok := mapClaims[CtxRequestHeaderUserId].(float64); ok { ctx.Set(CtxRequestHeaderUserId, int64(uid)) } else { ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, mapClaims[CtxRequestHeaderUserId].(float64) error"}) return } } else { ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, mapClaims[ctxRequestTokenExpired].(float64) error"}) return } } else { ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"msg": "auth failed, token.Claims.(jwt.MapClaims) error"}) return } } }