package system import ( "context" "errors" "strings" "kra/internal/conf" ) // Api API实体 type Api struct { ID uint Path string Description string ApiGroup string Method string } // IgnoreApi 忽略的API type IgnoreApi struct { Path string Method string } // CasbinRule Casbin规则 type CasbinRule struct { Path string Method string } // ApiRepo API仓储接口 type ApiRepo interface { Create(ctx context.Context, api *Api) error Update(ctx context.Context, api *Api) error Delete(ctx context.Context, id uint) error DeleteByIds(ctx context.Context, ids []uint) error FindByID(ctx context.Context, id uint) (*Api, error) FindByPathMethod(ctx context.Context, path, method string) (*Api, error) List(ctx context.Context, page, pageSize int, filters map[string]string, orderKey string, desc bool) ([]*Api, int64, error) FindAll(ctx context.Context) ([]*Api, error) FindByIds(ctx context.Context, ids []uint) ([]*Api, error) GetApiGroups(ctx context.Context) ([]string, map[string]string, error) CreateIgnoreApi(ctx context.Context, path, method string) error DeleteIgnoreApi(ctx context.Context, path, method string) error FindAllIgnoreApis(ctx context.Context) ([]*IgnoreApi, error) } // CasbinRepo Casbin仓储接口 type CasbinRepo interface { ClearCasbin(v int, p ...string) bool UpdateCasbinApi(oldPath, newPath, oldMethod, newMethod string) error GetPolicyPathByAuthorityId(authorityId uint) []CasbinRule FreshCasbin() error AddPolicies(rules [][]string) error UpdateCasbin(adminAuthorityID, authorityId uint, casbinInfos []CasbinRule) error RemoveFilteredPolicy(authorityId string) error } // ApiUsecase API用例 type ApiUsecase struct { repo ApiRepo casbinRepo CasbinRepo authRepo AuthorityRepo useStrictAuth bool routers []RouterInfo // 内存中的路由信息 } // RouterInfo 路由信息 type RouterInfo struct { Path string Method string } // NewApiUsecase 创建API用例 func NewApiUsecase(repo ApiRepo, casbinRepo CasbinRepo, authRepo AuthorityRepo, useStrictAuth conf.UseStrictAuth) *ApiUsecase { return &ApiUsecase{ repo: repo, casbinRepo: casbinRepo, authRepo: authRepo, useStrictAuth: bool(useStrictAuth), routers: make([]RouterInfo, 0), } } // SetRouters 设置内存中的路由信息 func (uc *ApiUsecase) SetRouters(routers []RouterInfo) { uc.routers = routers } // CreateApi 创建API func (uc *ApiUsecase) CreateApi(ctx context.Context, api *Api) error { return uc.repo.Create(ctx, api) } // UpdateApi 更新API func (uc *ApiUsecase) UpdateApi(ctx context.Context, api *Api) error { // 获取旧记录 old, err := uc.repo.FindByID(ctx, api.ID) if err != nil { return err } // 如果路径或方法变更,更新Casbin if old.Path != api.Path || old.Method != api.Method { if err := uc.casbinRepo.UpdateCasbinApi(old.Path, api.Path, old.Method, api.Method); err != nil { return err } } return uc.repo.Update(ctx, api) } // DeleteApi 删除API func (uc *ApiUsecase) DeleteApi(ctx context.Context, id uint) error { api, err := uc.repo.FindByID(ctx, id) if err != nil { return err } if err := uc.repo.Delete(ctx, id); err != nil { return err } // 清除Casbin规则 uc.casbinRepo.ClearCasbin(1, api.Path, api.Method) return nil } // DeleteApisByIds 批量删除API func (uc *ApiUsecase) DeleteApisByIds(ctx context.Context, ids []uint) error { apis, err := uc.repo.FindByIds(ctx, ids) if err != nil { return err } if err := uc.repo.DeleteByIds(ctx, ids); err != nil { return err } // 清除Casbin规则 for _, api := range apis { uc.casbinRepo.ClearCasbin(1, api.Path, api.Method) } return nil } // GetApiById 根据ID获取API func (uc *ApiUsecase) GetApiById(ctx context.Context, id uint) (*Api, error) { return uc.repo.FindByID(ctx, id) } // GetAPIInfoList 分页获取API列表 func (uc *ApiUsecase) GetAPIInfoList(ctx context.Context, page, pageSize int, filters map[string]string, orderKey string, desc bool) ([]*Api, int64, error) { // 验证排序字段 if orderKey != "" { orderMap := map[string]bool{"id": true, "path": true, "api_group": true, "description": true, "method": true} if !orderMap[orderKey] { return nil, 0, errors.New("非法的排序字段: " + orderKey) } } return uc.repo.List(ctx, page, pageSize, filters, orderKey, desc) } // GetAllApis 获取所有API(根据权限过滤) func (uc *ApiUsecase) GetAllApis(ctx context.Context, authorityID uint) ([]*Api, error) { parentAuthorityID, err := uc.authRepo.GetParentAuthorityID(ctx, authorityID) if err != nil { return nil, err } apis, err := uc.repo.FindAll(ctx) if err != nil { return nil, err } // 如果是顶级角色或不使用严格权限,返回所有API if parentAuthorityID == 0 || !uc.useStrictAuth { return apis, nil } // 根据Casbin规则过滤 paths := uc.casbinRepo.GetPolicyPathByAuthorityId(authorityID) var authApis []*Api for _, api := range apis { for _, rule := range paths { if rule.Path == api.Path && rule.Method == api.Method { authApis = append(authApis, api) break } } } return authApis, nil } // GetApiGroups 获取API分组 func (uc *ApiUsecase) GetApiGroups(ctx context.Context) ([]string, map[string]string, error) { return uc.repo.GetApiGroups(ctx) } // SyncApi 同步API func (uc *ApiUsecase) SyncApi(ctx context.Context) (newApis, deleteApis, ignoreApis []*Api, err error) { newApis = make([]*Api, 0) deleteApis = make([]*Api, 0) ignoreApis = make([]*Api, 0) // 获取数据库中的API apis, err := uc.repo.FindAll(ctx) if err != nil { return nil, nil, nil, err } // 获取忽略的API ignores, err := uc.repo.FindAllIgnoreApis(ctx) if err != nil { return nil, nil, nil, err } for _, ig := range ignores { ignoreApis = append(ignoreApis, &Api{ Path: ig.Path, Method: ig.Method, }) } // 过滤掉忽略的路由 var cacheApis []*Api for _, r := range uc.routers { ignored := false for _, ig := range ignores { if ig.Path == r.Path && ig.Method == r.Method { ignored = true break } } if !ignored { cacheApis = append(cacheApis, &Api{ Path: r.Path, Method: r.Method, }) } } // 对比:内存中有但数据库没有的 -> 新增 for _, cache := range cacheApis { found := false for _, api := range apis { if cache.Path == api.Path && cache.Method == api.Method { found = true break } } if !found { newApis = append(newApis, &Api{ Path: cache.Path, Method: cache.Method, }) } } // 对比:数据库有但内存没有的 -> 删除 for _, api := range apis { found := false for _, cache := range cacheApis { if cache.Path == api.Path && cache.Method == api.Method { found = true break } } if !found { deleteApis = append(deleteApis, api) } } return newApis, deleteApis, ignoreApis, nil } // IgnoreApi 忽略/取消忽略API func (uc *ApiUsecase) IgnoreApi(ctx context.Context, path, method string, flag bool) error { if flag { return uc.repo.CreateIgnoreApi(ctx, path, method) } return uc.repo.DeleteIgnoreApi(ctx, path, method) } // EnterSyncApi 确认同步API func (uc *ApiUsecase) EnterSyncApi(ctx context.Context, newApis, deleteApis []*Api) error { // 创建新API for _, api := range newApis { if err := uc.repo.Create(ctx, api); err != nil { // 忽略重复错误 if !strings.Contains(err.Error(), "存在相同api") { return err } } } // 删除旧API for _, api := range deleteApis { uc.casbinRepo.ClearCasbin(1, api.Path, api.Method) existing, err := uc.repo.FindByPathMethod(ctx, api.Path, api.Method) if err == nil && existing != nil { if err := uc.repo.Delete(ctx, existing.ID); err != nil { return err } } } return nil } // FreshCasbin 刷新Casbin缓存 func (uc *ApiUsecase) FreshCasbin() error { return uc.casbinRepo.FreshCasbin() }