@@ -45,6 +45,94 @@ func (s *SystemApiApi) CreateApi(c *gin.Context) {
|
||||
response.OkWithMessage("创建成功", c)
|
||||
}
|
||||
|
||||
// SyncApi
|
||||
// @Tags SysApi
|
||||
// @Summary 同步API
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Success 200 {object} response.Response{msg=string} "同步API"
|
||||
// @Router /api/syncApi [get]
|
||||
func (s *SystemApiApi) SyncApi(c *gin.Context) {
|
||||
newApis, deleteApis, ignoreApis, err := apiService.SyncApi()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("同步失败!", zap.Error(err))
|
||||
response.FailWithMessage("同步失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(gin.H{
|
||||
"newApis": newApis,
|
||||
"deleteApis": deleteApis,
|
||||
"ignoreApis": ignoreApis,
|
||||
}, c)
|
||||
}
|
||||
|
||||
// GetApiGroups
|
||||
// @Tags SysApi
|
||||
// @Summary 获取API分组
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Success 200 {object} response.Response{msg=string} "获取API分组"
|
||||
// @Router /api/getApiGroups [post]
|
||||
func (s *SystemApiApi) GetApiGroups(c *gin.Context) {
|
||||
groups, err := apiService.GetApiGroups()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败", c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(groups, c)
|
||||
}
|
||||
|
||||
// IgnoreApi
|
||||
// @Tags IgnoreApi
|
||||
// @Summary 忽略API
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Success 200 {object} response.Response{msg=string} "同步API"
|
||||
// @Router /api/ignoreApi [post]
|
||||
func (s *SystemApiApi) IgnoreApi(c *gin.Context) {
|
||||
var ignoreApi system.SysIgnoreApi
|
||||
err := c.ShouldBindJSON(&ignoreApi)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
err = apiService.IgnoreApi(ignoreApi)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("忽略失败!", zap.Error(err))
|
||||
response.FailWithMessage("忽略失败", c)
|
||||
return
|
||||
}
|
||||
response.Ok(c)
|
||||
}
|
||||
|
||||
// EnterSyncApi
|
||||
// @Tags SysApi
|
||||
// @Summary 确认同步API
|
||||
// @Security ApiKeyAuth
|
||||
// @accept application/json
|
||||
// @Produce application/json
|
||||
// @Success 200 {object} response.Response{msg=string} "确认同步API"
|
||||
// @Router /api/enterSyncApi [post]
|
||||
func (s *SystemApiApi) EnterSyncApi(c *gin.Context) {
|
||||
var syncApi systemRes.SysSyncApis
|
||||
err := c.ShouldBindJSON(&syncApi)
|
||||
if err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
err = apiService.EnterSyncApi(syncApi)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("忽略失败!", zap.Error(err))
|
||||
response.FailWithMessage("忽略失败", c)
|
||||
return
|
||||
}
|
||||
response.Ok(c)
|
||||
}
|
||||
|
||||
// DeleteApi
|
||||
// @Tags SysApi
|
||||
// @Summary 删除api
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/qiniu/qmgo"
|
||||
"sync"
|
||||
|
||||
@@ -29,9 +30,9 @@ var (
|
||||
GVA_LOG *zap.Logger
|
||||
GVA_Timer timer.Timer = timer.NewTimerTask()
|
||||
GVA_Concurrency_Control = &singleflight.Group{}
|
||||
|
||||
BlackCache local_cache.Cache
|
||||
lock sync.RWMutex
|
||||
GVA_ROUTERS gin.RoutesInfo
|
||||
BlackCache local_cache.Cache
|
||||
lock sync.RWMutex
|
||||
)
|
||||
|
||||
// GetGlobalDBByDBName 通过名称获取db list中的db
|
||||
|
@@ -33,6 +33,7 @@ func RegisterTables() {
|
||||
err := db.AutoMigrate(
|
||||
|
||||
system.SysApi{},
|
||||
system.SysIgnoreApi{},
|
||||
system.SysUser{},
|
||||
system.SysBaseMenu{},
|
||||
system.JwtBlacklist{},
|
||||
|
@@ -103,6 +103,8 @@ func Routers() *gin.Engine {
|
||||
// 注册业务路由
|
||||
initBizRouter(PrivateGroup, PublicGroup)
|
||||
|
||||
global.GVA_ROUTERS = Router.Routes()
|
||||
|
||||
global.GVA_LOG.Info("router register success")
|
||||
return Router
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ func OkWithMessage(message string, c *gin.Context) {
|
||||
}
|
||||
|
||||
func OkWithData(data interface{}, c *gin.Context) {
|
||||
Result(SUCCESS, data, "查询成功", c)
|
||||
Result(SUCCESS, data, "成功", c)
|
||||
}
|
||||
|
||||
func OkWithDetailed(data interface{}, message string, c *gin.Context) {
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package response
|
||||
|
||||
import "github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
import (
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
)
|
||||
|
||||
type SysAPIResponse struct {
|
||||
Api system.SysApi `json:"api"`
|
||||
@@ -9,3 +11,8 @@ type SysAPIResponse struct {
|
||||
type SysAPIListResponse struct {
|
||||
Apis []system.SysApi `json:"apis"`
|
||||
}
|
||||
|
||||
type SysSyncApis struct {
|
||||
NewApis []system.SysApi `json:"newApis"`
|
||||
DeleteApis []system.SysApi `json:"deleteApis"`
|
||||
}
|
||||
|
@@ -15,3 +15,14 @@ type SysApi struct {
|
||||
func (SysApi) TableName() string {
|
||||
return "sys_apis"
|
||||
}
|
||||
|
||||
type SysIgnoreApi struct {
|
||||
global.GVA_MODEL
|
||||
Path string `json:"path" gorm:"comment:api路径"` // api路径
|
||||
Method string `json:"method" gorm:"default:POST;comment:方法"` // 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE
|
||||
Flag bool `json:"flag" gorm:"-"` // 是否忽略
|
||||
}
|
||||
|
||||
func (SysIgnoreApi) TableName() string {
|
||||
return "sys_ignore_apis"
|
||||
}
|
||||
|
@@ -15,6 +15,10 @@ func (s *ApiRouter) InitApiRouter(Router *gin.RouterGroup, RouterPub *gin.Router
|
||||
apiPublicRouterWithoutRecord := RouterPub.Group("api")
|
||||
apiRouterApi := v1.ApiGroupApp.SystemApiGroup.SystemApiApi
|
||||
{
|
||||
apiRouter.GET("getApiGroups", apiRouterApi.GetApiGroups) // 获取路由组
|
||||
apiRouter.GET("syncApi", apiRouterApi.SyncApi) // 同步Api
|
||||
apiRouter.POST("ignoreApi", apiRouterApi.IgnoreApi) // 忽略Api
|
||||
apiRouter.POST("enterSyncApi", apiRouterApi.EnterSyncApi) // 确认同步Api
|
||||
apiRouter.POST("createApi", apiRouterApi.CreateApi) // 创建Api
|
||||
apiRouter.POST("deleteApi", apiRouterApi.DeleteApi) // 删除Api
|
||||
apiRouter.POST("getApiById", apiRouterApi.GetApiById) // 获取单条Api消息
|
||||
|
@@ -3,11 +3,10 @@ package system
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/common/request"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
|
||||
systemRes "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@@ -28,6 +27,112 @@ func (apiService *ApiService) CreateApi(api system.SysApi) (err error) {
|
||||
return global.GVA_DB.Create(&api).Error
|
||||
}
|
||||
|
||||
func (apiService *ApiService) GetApiGroups() (groups []string, err error) {
|
||||
err = global.GVA_DB.Model(&system.SysApi{}).Select("DISTINCT api_group").Pluck("api_group", &groups).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (apiService *ApiService) SyncApi() (newApis, deleteApis, ignoreApis []system.SysApi, err error) {
|
||||
newApis = make([]system.SysApi, 0)
|
||||
deleteApis = make([]system.SysApi, 0)
|
||||
ignoreApis = make([]system.SysApi, 0)
|
||||
var apis []system.SysApi
|
||||
err = global.GVA_DB.Find(&apis).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var ignores []system.SysIgnoreApi
|
||||
err = global.GVA_DB.Find(&ignores).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i := range ignores {
|
||||
ignoreApis = append(ignoreApis, system.SysApi{
|
||||
Path: ignores[i].Path,
|
||||
Description: "",
|
||||
ApiGroup: "",
|
||||
Method: ignores[i].Method,
|
||||
})
|
||||
}
|
||||
|
||||
var cacheApis []system.SysApi
|
||||
for i := range global.GVA_ROUTERS {
|
||||
ignoresFlag := false
|
||||
for j := range ignores {
|
||||
if ignores[j].Path == global.GVA_ROUTERS[i].Path && ignores[j].Method == global.GVA_ROUTERS[i].Method {
|
||||
ignoresFlag = true
|
||||
}
|
||||
}
|
||||
if !ignoresFlag {
|
||||
cacheApis = append(cacheApis, system.SysApi{
|
||||
Path: global.GVA_ROUTERS[i].Path,
|
||||
Method: global.GVA_ROUTERS[i].Method,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//对比数据库中的api和内存中的api,如果数据库中的api不存在于内存中,则把api放入删除数组,如果内存中的api不存在于数据库中,则把api放入新增数组
|
||||
for i := range cacheApis {
|
||||
var flag bool
|
||||
// 如果存在于内存不存在于api数组中
|
||||
for j := range apis {
|
||||
if cacheApis[i].Path == apis[j].Path && cacheApis[i].Method == apis[j].Method {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
if !flag {
|
||||
newApis = append(newApis, system.SysApi{
|
||||
Path: cacheApis[i].Path,
|
||||
Description: "",
|
||||
ApiGroup: "",
|
||||
Method: cacheApis[i].Method,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for i := range apis {
|
||||
var flag bool
|
||||
// 如果存在于api数组不存在于内存
|
||||
for j := range cacheApis {
|
||||
if cacheApis[j].Path == apis[i].Path && cacheApis[j].Method == apis[i].Method {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
if !flag {
|
||||
deleteApis = append(deleteApis, apis[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (apiService *ApiService) IgnoreApi(ignoreApi system.SysIgnoreApi) (err error) {
|
||||
if ignoreApi.Flag {
|
||||
return global.GVA_DB.Create(&ignoreApi).Error
|
||||
}
|
||||
return global.GVA_DB.Unscoped().Delete(&ignoreApi, "path = ? AND method = ?", ignoreApi.Path, ignoreApi.Method).Error
|
||||
}
|
||||
|
||||
func (apiService *ApiService) EnterSyncApi(syncApis systemRes.SysSyncApis) (err error) {
|
||||
return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
|
||||
var txErr error
|
||||
if syncApis.NewApis != nil && len(syncApis.NewApis) > 0 {
|
||||
txErr = tx.Create(&syncApis.NewApis).Error
|
||||
if txErr != nil {
|
||||
return txErr
|
||||
}
|
||||
}
|
||||
for i := range syncApis.DeleteApis {
|
||||
CasbinServiceApp.ClearCasbin(1, syncApis.DeleteApis[i].Path, syncApis.DeleteApis[i].Method)
|
||||
txErr = tx.Delete(&system.SysApi{}, "path = ? AND method = ?", syncApis.DeleteApis[i].Path, syncApis.DeleteApis[i].Method).Error
|
||||
if txErr != nil {
|
||||
return txErr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
//@author: [piexlmax](https://github.com/piexlmax)
|
||||
//@function: DeleteApi
|
||||
//@description: 删除基础api
|
||||
@@ -44,9 +149,7 @@ func (apiService *ApiService) DeleteApi(api system.SysApi) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !CasbinServiceApp.ClearCasbin(1, entity.Path, entity.Method) {
|
||||
return errors.New("ClearCasbin 失败")
|
||||
}
|
||||
CasbinServiceApp.ClearCasbin(1, entity.Path, entity.Method)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -63,6 +63,10 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
|
||||
{ApiGroup: "api", Method: "POST", Path: "/api/getAllApis", Description: "获取所有api"},
|
||||
{ApiGroup: "api", Method: "POST", Path: "/api/getApiById", Description: "获取api详细信息"},
|
||||
{ApiGroup: "api", Method: "DELETE", Path: "/api/deleteApisByIds", Description: "批量删除api"},
|
||||
{ApiGroup: "api", Method: "GET", Path: "/api/syncApi", Description: "获取待同步API"},
|
||||
{ApiGroup: "api", Method: "GET", Path: "/api/getApiGroups", Description: "获取路由组"},
|
||||
{ApiGroup: "api", Method: "POST", Path: "/api/enterSyncApi", Description: "确认同步API"},
|
||||
{ApiGroup: "api", Method: "POST", Path: "/api/ignoreApi", Description: "忽略API"},
|
||||
|
||||
{ApiGroup: "角色", Method: "POST", Path: "/authority/copyAuthority", Description: "拷贝角色"},
|
||||
{ApiGroup: "角色", Method: "POST", Path: "/authority/createAuthority", Description: "创建角色"},
|
||||
@@ -145,7 +149,7 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
|
||||
{ApiGroup: "断点续传(插件版)", Method: "GET", Path: "/simpleUploader/mergeFileMd5", Description: "上传完成合并文件"},
|
||||
|
||||
{ApiGroup: "email", Method: "POST", Path: "/email/emailTest", Description: "发送测试邮件"},
|
||||
{ApiGroup: "email", Method: "POST", Path: "/email/emailSend", Description: "发送邮件示例"},
|
||||
{ApiGroup: "email", Method: "POST", Path: "/email/sendEmail", Description: "发送邮件"},
|
||||
|
||||
{ApiGroup: "按钮权限", Method: "POST", Path: "/authorityBtn/setAuthorityBtn", Description: "设置按钮权限"},
|
||||
{ApiGroup: "按钮权限", Method: "POST", Path: "/authorityBtn/getAuthorityBtn", Description: "获取已有按钮权限"},
|
||||
|
75
server/source/system/api_ignore.go
Normal file
75
server/source/system/api_ignore.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
sysModel "github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/service/system"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type initApiIgnore struct{}
|
||||
|
||||
const initOrderApiIgnore = initOrderApi + 1
|
||||
|
||||
// auto run
|
||||
func init() {
|
||||
system.RegisterInit(initOrderApiIgnore, &initApiIgnore{})
|
||||
}
|
||||
|
||||
func (i initApiIgnore) InitializerName() string {
|
||||
return sysModel.SysIgnoreApi{}.TableName()
|
||||
}
|
||||
|
||||
func (i *initApiIgnore) MigrateTable(ctx context.Context) (context.Context, error) {
|
||||
db, ok := ctx.Value("db").(*gorm.DB)
|
||||
if !ok {
|
||||
return ctx, system.ErrMissingDBContext
|
||||
}
|
||||
return ctx, db.AutoMigrate(&sysModel.SysIgnoreApi{})
|
||||
}
|
||||
|
||||
func (i *initApiIgnore) TableCreated(ctx context.Context) bool {
|
||||
db, ok := ctx.Value("db").(*gorm.DB)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return db.Migrator().HasTable(&sysModel.SysIgnoreApi{})
|
||||
}
|
||||
|
||||
func (i *initApiIgnore) InitializeData(ctx context.Context) (context.Context, error) {
|
||||
db, ok := ctx.Value("db").(*gorm.DB)
|
||||
if !ok {
|
||||
return ctx, system.ErrMissingDBContext
|
||||
}
|
||||
entities := []sysModel.SysIgnoreApi{
|
||||
{Method: "GET", Path: "/swagger/*any"},
|
||||
{Method: "GET", Path: "/api/freshCasbin"},
|
||||
{Method: "GET", Path: "/uploads/file/*filepath"},
|
||||
{Method: "GET", Path: "/health"},
|
||||
{Method: "HEAD", Path: "/uploads/file/*filepath"},
|
||||
{Method: "POST", Path: "/autoCode/llmAuto"},
|
||||
{Method: "POST", Path: "/system/reloadSystem"},
|
||||
{Method: "POST", Path: "/base/login"},
|
||||
{Method: "POST", Path: "/base/captcha"},
|
||||
{Method: "POST", Path: "/init/initdb"},
|
||||
{Method: "POST", Path: "/init/checkdb"},
|
||||
}
|
||||
if err := db.Create(&entities).Error; err != nil {
|
||||
return ctx, errors.Wrap(err, sysModel.SysIgnoreApi{}.TableName()+"表数据初始化失败!")
|
||||
}
|
||||
next := context.WithValue(ctx, i.InitializerName(), entities)
|
||||
return next, nil
|
||||
}
|
||||
|
||||
func (i *initApiIgnore) DataInserted(ctx context.Context) bool {
|
||||
db, ok := ctx.Value("db").(*gorm.DB)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if errors.Is(db.Where("path = ? AND method = ?", "/swagger/*any", "GET").
|
||||
First(&sysModel.SysIgnoreApi{}).Error, gorm.ErrRecordNotFound) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
@@ -9,7 +9,7 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const initOrderCasbin = initOrderApi + 1
|
||||
const initOrderCasbin = initOrderApiIgnore + 1
|
||||
|
||||
type initCasbin struct{}
|
||||
|
||||
@@ -54,6 +54,10 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
|
||||
{Ptype: "p", V0: "888", V1: "/api/updateApi", V2: "POST"},
|
||||
{Ptype: "p", V0: "888", V1: "/api/getAllApis", V2: "POST"},
|
||||
{Ptype: "p", V0: "888", V1: "/api/deleteApisByIds", V2: "DELETE"},
|
||||
{Ptype: "p", V0: "888", V1: "/api/syncApi", V2: "GET"},
|
||||
{Ptype: "p", V0: "888", V1: "/api/getApiGroups", V2: "GET"},
|
||||
{Ptype: "p", V0: "888", V1: "/api/enterSyncApi", V2: "POST"},
|
||||
{Ptype: "p", V0: "888", V1: "/api/ignoreApi", V2: "POST"},
|
||||
|
||||
{Ptype: "p", V0: "888", V1: "/authority/copyAuthority", V2: "POST"},
|
||||
{Ptype: "p", V0: "888", V1: "/authority/updateAuthority", V2: "PUT"},
|
||||
@@ -143,6 +147,7 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
|
||||
{Ptype: "p", V0: "888", V1: "/sysOperationRecord/deleteSysOperationRecordByIds", V2: "DELETE"},
|
||||
|
||||
{Ptype: "p", V0: "888", V1: "/email/emailTest", V2: "POST"},
|
||||
{Ptype: "p", V0: "888", V1: "/email/sendEmail", V2: "POST"},
|
||||
|
||||
{Ptype: "p", V0: "888", V1: "/simpleUploader/upload", V2: "POST"},
|
||||
{Ptype: "p", V0: "888", V1: "/simpleUploader/checkFileMd5", V2: "GET"},
|
||||
|
Reference in New Issue
Block a user