TODO: fix middleware nil point

This commit is contained in:
Twilight 2024-06-13 16:36:10 +08:00
parent 57662079f6
commit 574d25691c
13 changed files with 179 additions and 60 deletions

View File

@ -1 +0,0 @@
package access

View File

@ -0,0 +1,8 @@
package consts
type BaseResponse struct {
Message string `json:"message"`
Error string `json:"error,omitempty"`
Code int `json:"code"`
Data any `json:"data,omitempty"`
}

View File

@ -4,7 +4,7 @@ import (
"github.com/gin-gonic/gin"
)
type Metadata struct {
type Request struct {
Http *gin.Context
User *UserTokenInfo
}

View File

@ -22,3 +22,5 @@ type UserTokenInfo struct {
Email string `json:"email"`
Groups []string `json:"groups"`
}
const UserTokenInfoKey = "user.jwt"

View File

@ -0,0 +1,32 @@
package helper
import (
"framework_v2/internal/consts"
"github.com/gin-gonic/gin"
)
func ResponseMessage(c *gin.Context, code int, message string, data interface{}) {
c.JSON(code, &consts.BaseResponse{
Message: message,
Code: code,
Data: data,
})
c.Abort()
}
func Response(c *gin.Context, code int, data interface{}) {
c.JSON(code, &consts.BaseResponse{
Code: code,
Data: data,
})
c.Abort()
}
func ResponseError(c *gin.Context, code int, err error) {
c.JSON(code, &consts.BaseResponse{
Error: err.Error(),
Code: code,
})
c.Abort()
}

View File

@ -6,8 +6,9 @@ import (
"net/http"
)
func CurrentUser(req *consts.Metadata) {
func CurrentUser(req *consts.Request) {
req.Http.JSON(http.StatusOK, gin.H{
"req": req.User,
"req": req.User.Sub,
})
}

View File

@ -2,7 +2,7 @@ package http
import (
"framework_v2/internal/access"
"framework_v2/internal/http/routes"
"framework_v2/internal/providers"
)
func InitHttp() {
@ -10,5 +10,5 @@ func InitHttp() {
panic("You must call InitGin() before InitHttp()")
}
routes.InitApiRoutes()
providers.InitApiRoutes()
}

View File

@ -1,7 +0,0 @@
package routes
import "framework_v2/internal/http/controllers/user"
func InitApiRoutes() {
HandleRoute(GET, "/", user.CurrentUser)
}

View File

@ -1,45 +0,0 @@
package routes
import (
"framework_v2/internal/access"
"framework_v2/internal/consts"
"github.com/gin-gonic/gin"
)
type httpMethod int
var httpMethodStr = []string{"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}
func (h httpMethod) String() string {
return httpMethodStr[h-1]
}
const (
GET httpMethod = iota + 1
POST
PUT
DELETE
PATCH
HEAD
OPTIONS
)
type HandlerFunc func(metadata *consts.Metadata)
func HandleRoute(method httpMethod, relativePath string, controller HandlerFunc, middlewares ...gin.HandlerFunc) {
access.Router.Handle(method.String(), relativePath, func(c *gin.Context) {
for _, middleware := range middlewares {
middleware(c)
}
handleWithMetadata(c, controller)
})
}
func handleWithMetadata(c *gin.Context, controller HandlerFunc) {
var metadata = &consts.Metadata{
Http: c,
}
controller(metadata)
}

View File

@ -0,0 +1,9 @@
package providers
import (
"framework_v2/internal/http/controllers/user"
)
func InitApiRoutes() {
HandleRoute(GET, "/", user.CurrentUser, MiddlewareJWTAuth, MiddlewareJSONResponse)
}

View File

@ -2,6 +2,7 @@ package providers
import (
"framework_v2/internal/access"
"framework_v2/internal/consts"
ginzap "github.com/gin-contrib/zap"
"github.com/gin-gonic/gin"
"time"
@ -12,6 +13,48 @@ func InitGin() {
access.Router = gin.New()
access.Router.Use(gin.Recovery(), ginzap.Ginzap(access.Logger, time.RFC3339, true))
access.Router.Use(ginzap.RecoveryWithZap(access.Logger, true))
access.Router.Use(ginzap.Ginzap(access.Logger, time.RFC3339, true))
//access.Router.Use(gin.Recovery())
//access.Router.Use(ginzap.RecoveryWithZap(access.Logger, true))
}
type httpMethod int
var httpMethodStr = []string{"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"}
func (h httpMethod) String() string {
return httpMethodStr[h-1]
}
const (
GET httpMethod = iota + 1
POST
PUT
DELETE
PATCH
HEAD
OPTIONS
)
type HandlerFunc func(metadata *consts.Request)
func HandleRoute(method httpMethod, relativePath string, controller HandlerFunc, middlewares ...gin.HandlerFunc) {
access.Router.Handle(method.String(), relativePath, func(c *gin.Context) {
for _, middleware := range middlewares {
middleware(c)
}
if !c.IsAborted() {
handleWithMetadata(c, controller)
}
})
}
func handleWithMetadata(c *gin.Context, controller HandlerFunc) {
var metadata = &consts.Request{
Http: c,
User: GetAuthFromCtx(c),
}
controller(metadata)
}

View File

@ -0,0 +1,77 @@
package providers
import (
"errors"
"fmt"
"framework_v2/internal/consts"
"framework_v2/internal/helper"
"github.com/gin-gonic/gin"
"github.com/mitchellh/mapstructure"
"net/http"
"strings"
)
var (
ErrNotValidToken = errors.New("无效的 JWT 令牌。")
ErrJWTFormatError = errors.New("JWT 格式错误。")
ErrNotBearerType = errors.New("不是 Bearer 类型。")
)
const AnonymousUser = "anonymous"
func MiddlewareJWTAuth(c *gin.Context) {
var sub = AnonymousUser
var jwtIdToken = consts.UserTokenInfo{}
if Config.DebugMode.Enable {
jwtIdToken.Sub = sub
} else {
// get authorization header
authorization := c.Request.Header.Get("Authorization")
if authorization == "" {
helper.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
return
}
authSplit := strings.Split(authorization, " ")
if len(authSplit) != 2 {
helper.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
return
}
if authSplit[0] != "Bearer" {
helper.ResponseError(c, http.StatusUnauthorized, ErrNotBearerType)
return
}
token, err := ParseJWT(authSplit[1])
if err != nil {
helper.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
return
}
sub, err = token.Claims.GetSubject()
if err != nil {
helper.ResponseError(c, http.StatusUnauthorized, ErrNotValidToken)
return
}
err = mapstructure.Decode(token.Claims, &jwtIdToken)
if err != nil {
Logger.Error("Failed to map token claims to JwtIDToken struct.\nError: " + err.Error())
helper.ResponseError(c, http.StatusUnauthorized, ErrNotValidToken)
return
}
fmt.Println("test", jwtIdToken.Sub)
}
c.Set(consts.UserTokenInfoKey, jwtIdToken)
return
}
func MiddlewareJSONResponse(c *gin.Context) {
c.Header("Content-Type", "application/json; charset=utf-8")
c.Next()
}