All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 5m54s
106 lines
4.0 KiB
Go
106 lines
4.0 KiB
Go
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/perfect-panel/server/pkg/constant"
|
|
|
|
"github.com/perfect-panel/server/pkg/logger"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/perfect-panel/server/internal/config"
|
|
"github.com/perfect-panel/server/internal/svc"
|
|
"github.com/perfect-panel/server/pkg/jwt"
|
|
"github.com/perfect-panel/server/pkg/result"
|
|
"github.com/perfect-panel/server/pkg/tool"
|
|
"github.com/perfect-panel/server/pkg/xerr"
|
|
"github.com/pkg/errors"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
func AuthMiddleware(svc *svc.ServiceContext) func(c *gin.Context) {
|
|
return func(c *gin.Context) {
|
|
ctx := c.Request.Context()
|
|
|
|
jwtConfig := svc.Config.JwtAuth
|
|
// get token from header
|
|
token := c.GetHeader("Authorization")
|
|
if token == "" {
|
|
logger.WithContext(c.Request.Context()).Errorw("[AuthMiddleware] token empty", logger.Field("path", c.Request.URL.Path))
|
|
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.ErrorTokenEmpty), "Token Empty"))
|
|
c.Abort()
|
|
return
|
|
}
|
|
// parse token
|
|
claims, err := jwt.ParseJwtToken(token, jwtConfig.AccessSecret)
|
|
if err != nil {
|
|
logger.WithContext(c.Request.Context()).Errorw("[AuthMiddleware] parse token failed", logger.Field("error", err.Error()))
|
|
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.ErrorTokenExpire), "Token Invalid"))
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
loginType := ""
|
|
if claims["LoginType"] != nil {
|
|
loginType = claims["LoginType"].(string)
|
|
}
|
|
// get user id from token
|
|
userId := int64(claims["UserId"].(float64))
|
|
// get session id from token
|
|
sessionId := claims["SessionId"].(string)
|
|
// get device id from token
|
|
var deviceId int64
|
|
if claims["DeviceId"] != nil {
|
|
deviceId = int64(claims["DeviceId"].(float64))
|
|
}
|
|
// get session id from redis
|
|
sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId)
|
|
value, err := svc.Redis.Get(c, sessionIdCacheKey).Result()
|
|
if err != nil {
|
|
if errors.Is(err, redis.Nil) {
|
|
logger.WithContext(c.Request.Context()).Infow("[AuthMiddleware] session not found", logger.Field("sessionId", sessionId))
|
|
} else {
|
|
logger.WithContext(c.Request.Context()).Errorw("[AuthMiddleware] redis get failed", logger.Field("error", err.Error()), logger.Field("sessionId", sessionId))
|
|
}
|
|
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access"))
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
//verify user id
|
|
if value != fmt.Sprintf("%v", userId) {
|
|
logger.WithContext(c.Request.Context()).Errorw("[AuthMiddleware] user mismatch", logger.Field("userId", userId), logger.Field("sessionId", sessionId), logger.Field("value", value))
|
|
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access"))
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
userInfo, err := svc.UserModel.FindOne(c, userId)
|
|
if err != nil {
|
|
logger.WithContext(c.Request.Context()).Errorw("[AuthMiddleware] user find failed", logger.Field("error", err.Error()), logger.Field("userId", userId))
|
|
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Database Query Error"))
|
|
c.Abort()
|
|
return
|
|
}
|
|
// admin verify
|
|
paths := strings.Split(c.Request.URL.Path, "/")
|
|
if tool.StringSliceContains(paths, "admin") && !*userInfo.IsAdmin {
|
|
logger.WithContext(c.Request.Context()).Errorw("[AuthMiddleware] not admin", logger.Field("userId", userId), logger.Field("sessionId", sessionId))
|
|
result.HttpResult(c, nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access"))
|
|
c.Abort()
|
|
return
|
|
}
|
|
logger.WithContext(c.Request.Context()).Infow("[AuthMiddleware] auth ok", logger.Field("userId", userId), logger.Field("loginType", loginType), logger.Field("path", c.Request.URL.Path))
|
|
ctx = context.WithValue(ctx, constant.LoginType, loginType)
|
|
ctx = context.WithValue(ctx, constant.CtxKeyUser, userInfo)
|
|
ctx = context.WithValue(ctx, constant.CtxKeySessionID, sessionId)
|
|
if deviceId > 0 {
|
|
ctx = context.WithValue(ctx, constant.CtxKeyDeviceID, deviceId)
|
|
}
|
|
c.Request = c.Request.WithContext(ctx)
|
|
c.Next()
|
|
}
|
|
}
|