|
|
@@ -1,8 +1,17 @@
|
|
|
package api
|
|
|
|
|
|
import (
|
|
|
- "github.com/gin-gonic/gin"
|
|
|
+ "errors"
|
|
|
"net/http"
|
|
|
+ "net/url"
|
|
|
+ "reflect"
|
|
|
+ "regexp"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+
|
|
|
+ "git.sxidc.com/go-framework/baize/framework/core/infrastructure/logger"
|
|
|
+ "git.sxidc.com/go-tools/utils/strutils"
|
|
|
+ "github.com/gin-gonic/gin"
|
|
|
)
|
|
|
|
|
|
// Handler 请求处理函数
|
|
|
@@ -30,11 +39,43 @@ type Router interface {
|
|
|
|
|
|
// BasePath 路由的基础路径,即去掉http://ip:port之后的URL部分(不包括AddRoute的RelativePath)
|
|
|
BasePath() string
|
|
|
+
|
|
|
+ // DumpPermissionItems 获取权限条目
|
|
|
+ DumpPermissionItems() []PermissionItem
|
|
|
+}
|
|
|
+
|
|
|
+type PermissionItem struct {
|
|
|
+ Group string `json:"group"`
|
|
|
+ Name string `json:"name"`
|
|
|
+ Description string `json:"description"`
|
|
|
+ Resource string `json:"resource"`
|
|
|
+ Action string `json:"action"`
|
|
|
+ NeedCheckExpire bool `json:"needCheckExpire"`
|
|
|
+ SensitiveWordScene int `json:"sensitiveWordScene"`
|
|
|
+}
|
|
|
+
|
|
|
+func (p *PermissionItem) check() error {
|
|
|
+ if strutils.IsStringEmpty(p.Name) {
|
|
|
+ return errors.New("没有权限条目名称")
|
|
|
+ }
|
|
|
+
|
|
|
+ if strutils.IsStringEmpty(p.Resource) {
|
|
|
+ return errors.New("没有权限条目resource")
|
|
|
+ }
|
|
|
+
|
|
|
+ if strutils.IsStringEmpty(p.Action) {
|
|
|
+ return errors.New("没有权限条目action")
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
type RootRouter struct {
|
|
|
engine *gin.Engine
|
|
|
versioned map[string]*PrefixRouter
|
|
|
+
|
|
|
+ // 由于gin的router的保证,不会有重复的条目
|
|
|
+ permissionItems []PermissionItem
|
|
|
}
|
|
|
|
|
|
func newRootRouter(engine *gin.Engine) *RootRouter {
|
|
|
@@ -72,8 +113,22 @@ func (r *RootRouter) VersionedRouter(version string) Router {
|
|
|
return r.versioned[version]
|
|
|
}
|
|
|
|
|
|
-func (r *RootRouter) AddRoute(method string, relativePath string, handlers ...Handler) Router {
|
|
|
+func (r *RootRouter) DumpPermissionItems() []PermissionItem {
|
|
|
+ return r.permissionItems
|
|
|
+}
|
|
|
+
|
|
|
+func (r *RootRouter) AddRoute(method string, relativePathPattern string, handlers ...Handler) Router {
|
|
|
+ relativePath, permissionItem, err := parseRelativePathPerm(r.engine.BasePath(), relativePathPattern, method)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+
|
|
|
r.engine.Handle(method, relativePath, transferHandlers(handlers...)...)
|
|
|
+
|
|
|
+ if permissionItem != nil {
|
|
|
+ r.permissionItems = append(r.permissionItems, *permissionItem)
|
|
|
+ }
|
|
|
+
|
|
|
return r
|
|
|
}
|
|
|
|
|
|
@@ -84,6 +139,9 @@ func (r *RootRouter) ServerHttp(w http.ResponseWriter, req *http.Request) {
|
|
|
type PrefixRouter struct {
|
|
|
groupRouter *gin.RouterGroup
|
|
|
versioned map[string]*PrefixRouter
|
|
|
+
|
|
|
+ // 由于gin的router的保证,不会有重复的条目
|
|
|
+ permissionItems []PermissionItem
|
|
|
}
|
|
|
|
|
|
func newPrefixRouter(group *gin.RouterGroup) *PrefixRouter {
|
|
|
@@ -117,8 +175,18 @@ func (r *PrefixRouter) VersionedRouter(version string) Router {
|
|
|
return r.versioned[version]
|
|
|
}
|
|
|
|
|
|
-func (r *PrefixRouter) AddRoute(method string, relativePath string, handlers ...Handler) Router {
|
|
|
+func (r *PrefixRouter) AddRoute(method string, relativePathPattern string, handlers ...Handler) Router {
|
|
|
+ relativePath, permissionItem, err := parseRelativePathPerm(r.groupRouter.BasePath(), relativePathPattern, method)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+
|
|
|
r.groupRouter.Handle(method, relativePath, transferHandlers(handlers...)...)
|
|
|
+
|
|
|
+ if permissionItem != nil {
|
|
|
+ r.permissionItems = append(r.permissionItems, *permissionItem)
|
|
|
+ }
|
|
|
+
|
|
|
return r
|
|
|
}
|
|
|
|
|
|
@@ -134,6 +202,10 @@ func (r *PrefixRouter) BasePath() string {
|
|
|
return r.groupRouter.BasePath()
|
|
|
}
|
|
|
|
|
|
+func (r *PrefixRouter) DumpPermissionItems() []PermissionItem {
|
|
|
+ return r.permissionItems
|
|
|
+}
|
|
|
+
|
|
|
func transferHandlers(handlers ...Handler) []gin.HandlerFunc {
|
|
|
ginHandlers := make([]gin.HandlerFunc, 0)
|
|
|
for _, handler := range handlers {
|
|
|
@@ -145,3 +217,93 @@ func transferHandlers(handlers ...Handler) []gin.HandlerFunc {
|
|
|
|
|
|
return ginHandlers
|
|
|
}
|
|
|
+
|
|
|
+const (
|
|
|
+ tagPartSeparator = ";"
|
|
|
+ tagPartKeyValueSeparator = ":"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ permTagKey = "perm"
|
|
|
+ permTagPartGroup = "group"
|
|
|
+ permTagPartName = "name"
|
|
|
+ permTagPartDescription = "description"
|
|
|
+ permTagPartNeedCheckExpire = "needCheckExpire"
|
|
|
+ permTagPartSensitiveWordScene = "sensitiveWordScene"
|
|
|
+)
|
|
|
+
|
|
|
+func parseRelativePathPerm(basePath string, relativePathPattern string, method string) (string, *PermissionItem, error) {
|
|
|
+ re := regexp.MustCompile(`\$\{(.+)\}\$`)
|
|
|
+ matches := re.FindStringSubmatch(relativePathPattern)
|
|
|
+
|
|
|
+ if len(matches) == 1 {
|
|
|
+ return relativePathPattern, nil, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ relativePath := re.ReplaceAllString(relativePathPattern, "")
|
|
|
+ permTag, ok := reflect.StructTag(matches[1]).Lookup(permTagKey)
|
|
|
+ if !ok {
|
|
|
+ return relativePath, nil, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ tagParts := strings.Split(permTag, tagPartSeparator)
|
|
|
+ if tagParts == nil || len(tagParts) == 0 {
|
|
|
+ return relativePath, nil, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ fullPath, err := url.JoinPath(basePath, relativePath)
|
|
|
+ if err != nil {
|
|
|
+ return "", nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ permissionItem := &PermissionItem{
|
|
|
+ Group: "",
|
|
|
+ Name: "",
|
|
|
+ Description: "",
|
|
|
+ Resource: fullPath,
|
|
|
+ Action: method,
|
|
|
+ NeedCheckExpire: false,
|
|
|
+ SensitiveWordScene: 0,
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tagPart := range tagParts {
|
|
|
+ tagPartKeyValue := strings.SplitN(strings.TrimSpace(tagPart), tagPartKeyValueSeparator, 2)
|
|
|
+
|
|
|
+ if strutils.IsStringEmpty(tagPartKeyValue[0]) {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ switch tagPartKeyValue[0] {
|
|
|
+ case permTagPartGroup:
|
|
|
+ permissionItem.Group = tagPartKeyValue[1]
|
|
|
+ case permTagPartName:
|
|
|
+ permissionItem.Name = tagPartKeyValue[1]
|
|
|
+ case permTagPartDescription:
|
|
|
+ permissionItem.Description = tagPartKeyValue[1]
|
|
|
+ case permTagPartNeedCheckExpire:
|
|
|
+ permissionItem.NeedCheckExpire = true
|
|
|
+ case permTagPartSensitiveWordScene:
|
|
|
+ scene, err := strconv.Atoi(tagPartKeyValue[1])
|
|
|
+ if err != nil {
|
|
|
+ return relativePath, nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ if scene < 1 || scene > 4 {
|
|
|
+ return relativePath, nil, errors.New("不支持的敏感词场景: " + tagPartKeyValue[1])
|
|
|
+ }
|
|
|
+
|
|
|
+ permissionItem.SensitiveWordScene = scene
|
|
|
+ default:
|
|
|
+ err := errors.New(permTagKey + "不支持的tag: " + tagPartKeyValue[0])
|
|
|
+ logger.GetInstance().Error(err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ err = permissionItem.check()
|
|
|
+ if err != nil {
|
|
|
+ return "", nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ return relativePath, permissionItem, nil
|
|
|
+}
|