Merge branch 'iot'

# Conflicts:
#	apps/develop/api/gen.go
#	apps/develop/api/table.go
#	apps/develop/router/gen.go
#	apps/develop/router/table.go
#	apps/job/api/job.go
#	apps/job/entity/job.go
#	apps/job/entity/log_job.go
#	apps/job/jobs/jobbase.go
#	apps/job/router/job.go
#	apps/log/api/log_job.go
#	apps/log/api/log_login.go
#	apps/log/api/log_oper.go
#	apps/log/router/log.go
#	apps/log/services/log_job.go
#	apps/resource/api/email.go
#	apps/resource/api/oss.go
#	apps/resource/router/email.go
#	apps/resource/router/oss.go
#	apps/system/api/api.go
#	apps/system/api/config.go
#	apps/system/api/dept.go
#	apps/system/api/dict.go
#	apps/system/api/menu.go
#	apps/system/api/notice.go
#	apps/system/api/post.go
#	apps/system/api/role.go
#	apps/system/api/system.go
#	apps/system/api/tenant.go
#	apps/system/api/user.go
#	apps/system/router/api.go
#	apps/system/router/config.go
#	apps/system/router/dept.go
#	apps/system/router/dict.go
#	apps/system/router/menu.go
#	apps/system/router/notice.go
#	apps/system/router/post.go
#	apps/system/router/role.go
#	apps/system/router/tenant.go
#	apps/system/router/user.go
#	go.mod
#	go.sum
#	main.go
#	pkg/config/app.go
#	pkg/config/casbin.go
#	pkg/config/config.go
#	pkg/config/db.go
#	pkg/config/gen.go
#	pkg/config/jwt.go
#	pkg/config/log.go
#	pkg/config/redis.go
#	pkg/config/server.go
#	pkg/global/global.go
#	pkg/initialize/table.go
#	pkg/middleware/log.go
#	pkg/middleware/oper.go
#	pkg/middleware/permission.go
#	resource/template/go/api.template
#	resource/template/go/router.template
#	resource/template/go/service.template
This commit is contained in:
XM-GO
2023-08-22 15:47:45 +08:00
227 changed files with 19473 additions and 17369 deletions

View File

@@ -1,27 +1,17 @@
package middleware
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/emicklei/go-restful/v3"
)
// 处理跨域请求,支持options访问
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin")
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id")
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS,DELETE,PUT")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
func Cors(wsContainer *restful.Container) restful.CrossOriginResourceSharing {
cors := restful.CrossOriginResourceSharing{
ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
AllowedHeaders: []string{"Content-Type", "AccessToken", "X-CSRF-Token", "Authorization", "Token", "X-Token", "X-User-Id"},
AllowedMethods: []string{"POST", "GET", "OPTIONS", "DELETE", "PUT"},
CookiesAllowed: false,
Container: wsContainer}
// 放行所有OPTIONS方法
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
// 处理请求
c.Next()
}
return cors
}

View File

@@ -0,0 +1,17 @@
package middleware
import (
"github.com/emicklei/go-restful/v3"
"html"
)
// 防止XSS攻击
func EscapeHTML(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
// 获取请求参数中的HTML标签
for _, p := range req.Request.URL.Query() {
escaped := html.EscapeString(p[0])
// 将转义后的参数重新设置到请求参数中
req.Request.URL.Query().Set(p[0], escaped)
}
chain.ProcessFilter(req, resp)
}

70
pkg/middleware/log.go Normal file
View File

@@ -0,0 +1,70 @@
package middleware
import (
"encoding/json"
"fmt"
"github.com/XM-GO/PandaKit/biz"
"github.com/XM-GO/PandaKit/logger"
"github.com/XM-GO/PandaKit/restfulx"
"github.com/XM-GO/PandaKit/utils"
"github.com/sirupsen/logrus"
"reflect"
"runtime/debug"
)
func LogHandler(rc *restfulx.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.Request.Request
lfs[req.Method] = req.URL.Path
if err := rc.Err; err != nil {
logger.Log.WithFields(lfs).Error(getErrMsg(rc, err))
return nil
}
logger.Log.WithFields(lfs).Info(getLogMsg(rc))
return nil
}
func getLogMsg(rc *restfulx.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 *restfulx.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)
}

View File

@@ -0,0 +1,46 @@
package middleware
import (
"github.com/XM-GO/PandaKit/biz"
"github.com/XM-GO/PandaKit/casbin"
"github.com/XM-GO/PandaKit/restfulx"
"github.com/XM-GO/PandaKit/token"
"github.com/dgrijalva/jwt-go"
"pandax/pkg/global"
)
func PermissionHandler(rc *restfulx.ReqCtx) error {
permission := rc.RequiredPermission
// 如果需要的权限信息不为空并且不需要token则不返回错误继续后续逻辑
if permission != nil && !permission.NeedToken {
return nil
}
tokenStr := rc.Request.Request.Header.Get("X-TOKEN")
// header不存在则从查询参数token中获取
if tokenStr == "" {
tokenStr = rc.Request.QueryParameter("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
}
ca := casbin.CasbinS{ModelPath: global.Conf.Casbin.ModelPath}
e := ca.Casbin()
// 判断策略中是否存在
success, err := e.Enforce(loginAccount.RoleKey, rc.Request.Request.URL.Path, rc.Request.Request.Method)
if !success {
return biz.CasbinErr
}
return nil
}

View File

@@ -2,7 +2,7 @@ package middleware
import (
"github.com/didip/tollbooth"
"github.com/gin-gonic/gin"
"github.com/emicklei/go-restful/v3"
"pandax/pkg/global"
)
@@ -12,17 +12,14 @@ import (
* @Date 2022/1/19 8:28
**/
//限流中间件
func Rate() gin.HandlerFunc {
//Rate 限流中间件
func Rate(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
lmt := tollbooth.NewLimiter(global.Conf.Server.Rate.RateNum, nil)
lmt.SetMessage("已经超出接口请求限制,稍后再试.")
return func(c *gin.Context) {
httpError := tollbooth.LimitByRequest(lmt, c.Writer, c.Request)
if httpError != nil {
c.Data(httpError.StatusCode, lmt.GetMessageContentType(), []byte(httpError.Message))
c.Abort()
} else {
c.Next()
}
httpError := tollbooth.LimitByRequest(lmt, resp, req.Request)
if httpError != nil {
resp.WriteErrorString(httpError.StatusCode, httpError.Message)
return
}
chain.ProcessFilter(req, resp)
}

44
pkg/middleware/swagger.go Normal file
View File

@@ -0,0 +1,44 @@
package middleware
import (
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
"github.com/go-openapi/spec"
)
/**
* @Description
* @Author 熊猫
* @Date 2022/8/3 9:16
**/
func SwaggerConfig(wsContainer *restful.Container) {
config := restfulspec.Config{
WebServices: wsContainer.RegisteredWebServices(),
APIPath: "/apidocs.json",
PostBuildSwaggerObjectHandler: enrichSwaggerObject}
wsContainer.Add(restfulspec.NewOpenAPIService(config))
}
func enrichSwaggerObject(swo *spec.Swagger) {
swo.Info = &spec.Info{
InfoProps: spec.InfoProps{
Title: "PandaX 框架的API文档",
Description: "这是PandaX框架文档根据文档调用API",
Contact: &spec.ContactInfo{
ContactInfoProps: spec.ContactInfoProps{
Name: "PandaX 熊猫",
Email: "2417920382@qq.com",
URL: "https://github.com/XM-GO/PandaX",
},
},
License: &spec.License{
LicenseProps: spec.LicenseProps{
Name: "MIT",
URL: "https://github.com/XM-GO/PandaX",
},
},
Version: "1.0.0",
},
}
}