mirror of
https://gitee.com/XM-GO/PandaX.git
synced 2026-05-06 03:51:25 +08:00
【更新】更新
This commit is contained in:
@@ -24,6 +24,7 @@ func BindQuery(g *gin.Context, data any) {
|
||||
panic(any(biz.NewBizErr(err.Error())))
|
||||
}
|
||||
}
|
||||
|
||||
func ParamsToAny(g *gin.Context, in any) {
|
||||
vars := make(map[string]any)
|
||||
for _, v := range g.Params {
|
||||
|
||||
84
base/ginx/log_handler.go
Normal file
84
base/ginx/log_handler.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package ginx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"pandax/base/biz"
|
||||
"pandax/base/utils"
|
||||
"pandax/pkg/global"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type LogInfo struct {
|
||||
LogResp bool // 是否记录返回结果
|
||||
Description string // 请求描述
|
||||
}
|
||||
|
||||
func NewLogInfo(description string) *LogInfo {
|
||||
return &LogInfo{Description: description, LogResp: false}
|
||||
}
|
||||
|
||||
func (i *LogInfo) WithLogResp(logResp bool) *LogInfo {
|
||||
i.LogResp = logResp
|
||||
return i
|
||||
}
|
||||
|
||||
func LogHandler(rc *ReqCtx) error {
|
||||
li := rc.LogInfo
|
||||
if li == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
lfs := logrus.Fields{}
|
||||
if la := rc.LoginAccount; la != nil {
|
||||
lfs["uid"] = la.UserId
|
||||
lfs["uname"] = la.UserName
|
||||
}
|
||||
|
||||
req := rc.GinCtx.Request
|
||||
lfs[req.Method] = req.URL.Path
|
||||
|
||||
if err := rc.Err; err != nil {
|
||||
global.Log.WithFields(lfs).Error(getErrMsg(rc, err))
|
||||
return nil
|
||||
}
|
||||
global.Log.WithFields(lfs).Info(getLogMsg(rc))
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLogMsg(rc *ReqCtx) string {
|
||||
msg := rc.LogInfo.Description + fmt.Sprintf(" ->%dms", rc.timed)
|
||||
if !utils.IsBlank(reflect.ValueOf(rc.ReqParam)) {
|
||||
rb, _ := json.Marshal(rc.ReqParam)
|
||||
msg = msg + fmt.Sprintf("\n--> %s", string(rb))
|
||||
}
|
||||
|
||||
// 返回结果不为空,则记录返回结果
|
||||
if rc.LogInfo.LogResp && !utils.IsBlank(reflect.ValueOf(rc.ResData)) {
|
||||
respB, _ := json.Marshal(rc.ResData)
|
||||
msg = msg + fmt.Sprintf("\n<-- %s", string(respB))
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func getErrMsg(rc *ReqCtx, err any) string {
|
||||
msg := rc.LogInfo.Description
|
||||
if !utils.IsBlank(reflect.ValueOf(rc.ReqParam)) {
|
||||
rb, _ := json.Marshal(rc.ReqParam)
|
||||
msg = msg + fmt.Sprintf("\n--> %s", string(rb))
|
||||
}
|
||||
|
||||
var errMsg string
|
||||
switch t := err.(type) {
|
||||
case *biz.BizError:
|
||||
errMsg = fmt.Sprintf("\n<-e errCode: %d, errMsg: %s", t.Code(), t.Error())
|
||||
case error:
|
||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s\n%s", t.Error(), string(debug.Stack()))
|
||||
case string:
|
||||
errMsg = fmt.Sprintf("\n<-e errMsg: %s\n%s", t, string(debug.Stack()))
|
||||
}
|
||||
return (msg + errMsg)
|
||||
}
|
||||
60
base/ginx/permission_handler.go
Normal file
60
base/ginx/permission_handler.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package ginx
|
||||
|
||||
import (
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"pandax/base/biz"
|
||||
"pandax/base/casbin"
|
||||
"pandax/base/token"
|
||||
"pandax/pkg/global"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Permission struct {
|
||||
NeedToken bool // 是否需要token
|
||||
NeedCasbin bool // 是否进行权限 api路径权限验证
|
||||
}
|
||||
|
||||
func (p *Permission) WithNeedToken(needToken bool) *Permission {
|
||||
p.NeedToken = needToken
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *Permission) WithNeedCasBin(needCasBin bool) *Permission {
|
||||
p.NeedCasbin = needCasBin
|
||||
return p
|
||||
}
|
||||
|
||||
func PermissionHandler(rc *ReqCtx) error {
|
||||
permission := rc.RequiredPermission
|
||||
// 如果需要的权限信息不为空,并且不需要token,则不返回错误,继续后续逻辑
|
||||
if permission != nil && !permission.NeedToken {
|
||||
return nil
|
||||
}
|
||||
tokenStr := rc.GinCtx.Request.Header.Get("X-TOKEN")
|
||||
// header不存在则从查询参数token中获取
|
||||
if tokenStr == "" {
|
||||
tokenStr = rc.GinCtx.Query("token")
|
||||
}
|
||||
if tokenStr == "" {
|
||||
return biz.PermissionErr
|
||||
}
|
||||
j := token.NewJWT("", []byte(global.Conf.Jwt.Key), jwt.SigningMethodHS256)
|
||||
loginAccount, err := j.ParseToken(tokenStr)
|
||||
if err != nil || loginAccount == nil {
|
||||
return biz.PermissionErr
|
||||
}
|
||||
rc.LoginAccount = loginAccount
|
||||
|
||||
if !permission.NeedCasbin {
|
||||
return nil
|
||||
}
|
||||
e := casbin.Casbin()
|
||||
// 判断策略中是否存在
|
||||
tenantId := strconv.Itoa(int(rc.LoginAccount.TenantId))
|
||||
success, err := e.Enforce(tenantId, loginAccount.RoleKey, rc.GinCtx.Request.URL.Path, rc.GinCtx.Request.Method)
|
||||
if !success {
|
||||
return biz.CasbinErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
124
base/ginx/req_ctx.go
Normal file
124
base/ginx/req_ctx.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package ginx
|
||||
|
||||
import (
|
||||
"pandax/base/biz"
|
||||
"pandax/base/token"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 处理函数
|
||||
type HandlerFunc func(*ReqCtx)
|
||||
|
||||
type ReqCtx struct {
|
||||
GinCtx *gin.Context // gin context
|
||||
|
||||
// NeedToken bool // 是否需要token
|
||||
RequiredPermission *Permission // 需要的权限信息,默认为nil,需要校验token
|
||||
LoginAccount *token.Claims // 登录账号信息,只有校验token后才会有值
|
||||
|
||||
LogInfo *LogInfo // 日志相关信息
|
||||
ReqParam any // 请求参数,主要用于记录日志
|
||||
ResData any // 响应结果
|
||||
Err any // 请求错误
|
||||
|
||||
timed int64 // 执行时间
|
||||
noRes bool // 无需返回结果,即文件下载等
|
||||
}
|
||||
|
||||
func (rc *ReqCtx) Handle(handler HandlerFunc) {
|
||||
ginCtx := rc.GinCtx
|
||||
defer func() {
|
||||
var err any
|
||||
err = recover()
|
||||
if err != nil {
|
||||
rc.Err = err
|
||||
ErrorRes(ginCtx, err)
|
||||
}
|
||||
// 应用所有请求后置处理器
|
||||
ApplyHandlerInterceptor(afterHandlers, rc)
|
||||
}()
|
||||
biz.IsTrue(ginCtx != nil, "ginContext == nil")
|
||||
|
||||
// 默认为不记录请求参数,可在handler回调函数中覆盖赋值
|
||||
rc.ReqParam = 0
|
||||
// 默认响应结果为nil,可在handler中赋值
|
||||
rc.ResData = nil
|
||||
|
||||
// 调用请求前所有处理器
|
||||
err := ApplyHandlerInterceptor(beforeHandlers, rc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
begin := time.Now()
|
||||
handler(rc)
|
||||
rc.timed = time.Now().Sub(begin).Milliseconds()
|
||||
if !rc.noRes {
|
||||
SuccessRes(ginCtx, rc.ResData)
|
||||
}
|
||||
}
|
||||
|
||||
func (rc *ReqCtx) Download(filename string) {
|
||||
rc.noRes = true
|
||||
Download(rc.GinCtx, filename)
|
||||
}
|
||||
|
||||
// 新建请求上下文,默认需要校验token
|
||||
func NewReqCtx(g *gin.Context) *ReqCtx {
|
||||
return &ReqCtx{GinCtx: g, LogInfo: NewLogInfo("默认日志信息"), RequiredPermission: &Permission{NeedToken: true, NeedCasbin: true}}
|
||||
}
|
||||
|
||||
// 调用该方法设置请求描述,则默认记录日志,并不记录响应结果
|
||||
func (r *ReqCtx) WithLog(model string) *ReqCtx {
|
||||
r.LogInfo.Description = model
|
||||
return r
|
||||
}
|
||||
|
||||
// 设置请求上下文需要的权限信息
|
||||
func (r *ReqCtx) WithRequiredPermission(permission *Permission) *ReqCtx {
|
||||
r.RequiredPermission = permission
|
||||
return r
|
||||
}
|
||||
|
||||
// 是否需要token
|
||||
func (r *ReqCtx) WithNeedToken(needToken bool) *ReqCtx {
|
||||
r.RequiredPermission.NeedToken = needToken
|
||||
return r
|
||||
}
|
||||
|
||||
// 是否需要Casbin
|
||||
func (r *ReqCtx) WithNeedCasbin(needCasbin bool) *ReqCtx {
|
||||
r.RequiredPermission.NeedCasbin = needCasbin
|
||||
return r
|
||||
}
|
||||
|
||||
// 处理器拦截器函数
|
||||
type HandlerInterceptorFunc func(*ReqCtx) error
|
||||
type HandlerInterceptors []HandlerInterceptorFunc
|
||||
|
||||
var (
|
||||
beforeHandlers HandlerInterceptors
|
||||
afterHandlers HandlerInterceptors
|
||||
)
|
||||
|
||||
// 使用前置处理器函数
|
||||
func UseBeforeHandlerInterceptor(b HandlerInterceptorFunc) {
|
||||
beforeHandlers = append(beforeHandlers, b)
|
||||
}
|
||||
|
||||
// 使用后置处理器函数
|
||||
func UseAfterHandlerInterceptor(b HandlerInterceptorFunc) {
|
||||
afterHandlers = append(afterHandlers, b)
|
||||
}
|
||||
|
||||
// 应用指定处理器拦截器,如果有一个错误则直接返回错误
|
||||
func ApplyHandlerInterceptor(his HandlerInterceptors, rc *ReqCtx) any {
|
||||
for _, handler := range his {
|
||||
if err := handler(rc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user