diff --git a/devcloud/etc/application.toml b/devcloud/etc/application.toml
index 88d097b..3c7ce50 100644
--- a/devcloud/etc/application.toml
+++ b/devcloud/etc/application.toml
@@ -11,7 +11,7 @@
database = "devcloud_go18"
username = "root"
password = "123456"
- auto_migrate = false
+ auto_migrate = true
debug = true
[http]
diff --git a/devcloud/mcenter/apps/endpoint/README.md b/devcloud/mcenter/apps/endpoint/README.md
index a129146..130c3ea 100644
--- a/devcloud/mcenter/apps/endpoint/README.md
+++ b/devcloud/mcenter/apps/endpoint/README.md
@@ -1,2 +1,17 @@
# 接口管理
+如何提取 当前这个服务的路由条目, GoRestful框架的Container这一层 获取
+
+```go
+func NewEntryFromRestfulContainer(c *restful.Container) (entries []*RouteEntry) {
+ wss := c.RegisteredWebServices()
+ for i := range wss {
+ for _, route := range wss[i].Routes() {
+ es := NewEntryFromRestRoute(route)
+ entries = append(entries, es)
+ }
+ }
+ return entries
+}
+```
+
diff --git a/devcloud/mcenter/apps/endpoint/impl/endpoint.go b/devcloud/mcenter/apps/endpoint/impl/endpoint.go
new file mode 100644
index 0000000..436cf8b
--- /dev/null
+++ b/devcloud/mcenter/apps/endpoint/impl/endpoint.go
@@ -0,0 +1,92 @@
+package impl
+
+import (
+ "context"
+
+ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint"
+ "github.com/infraboard/mcube/v2/exception"
+ "github.com/infraboard/mcube/v2/ioc/config/datasource"
+ "github.com/infraboard/mcube/v2/types"
+ "gorm.io/gorm"
+)
+
+// 注册API接口
+// 这是一个批量接口, 一次添加多条记录
+// 需要保证事务: 同时成功,或者同时失败, MySQL事务
+func (i *EndpointServiceImpl) RegistryEndpoint(ctx context.Context, in *endpoint.RegistryEndpointRequest) (*types.Set[*endpoint.Endpoint], error) {
+ if err := in.Validate(); err != nil {
+ return nil, err
+ }
+
+ set := types.New[*endpoint.Endpoint]()
+ err := datasource.DBFromCtx(ctx).Transaction(func(tx *gorm.DB) error {
+ for i := range in.Items {
+ item := in.Items[i].BuildUUID()
+ ins := endpoint.NewEndpoint().SetRouteEntry(*item)
+
+ oldEnpoint := endpoint.NewEndpoint()
+ if err := tx.Where("uuid = ?", item.UUID).Take(oldEnpoint).Error; err != nil {
+ if err != gorm.ErrRecordNotFound {
+ return err
+ }
+
+ // 需要创建
+ if err := tx.Save(ins).Error; err != nil {
+ return err
+ }
+ } else {
+ // 需要更新
+ ins.Id = oldEnpoint.Id
+ if err := tx.Where("uuid = ?", item.UUID).Updates(ins).Error; err != nil {
+ return err
+ }
+
+ }
+ set.Add(ins)
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return set, nil
+}
+
+// 查询API接口列表
+func (i *EndpointServiceImpl) QueryEndpoint(ctx context.Context, in *endpoint.QueryEndpointRequest) (*types.Set[*endpoint.Endpoint], error) {
+ set := types.New[*endpoint.Endpoint]()
+
+ query := datasource.DBFromCtx(ctx).Model(&endpoint.Endpoint{})
+ if len(in.Services) > 0 && !in.IsMatchAllService() {
+ query = query.Where("service IN ?", in.Services)
+ }
+
+ err := query.Count(&set.Total).Error
+ if err != nil {
+ return nil, err
+ }
+
+ err = query.
+ Order("created_at desc").
+ Find(&set.Items).
+ Error
+ if err != nil {
+ return nil, err
+ }
+ return set, nil
+}
+
+// 查询API接口详情
+func (i *EndpointServiceImpl) DescribeEndpoint(ctx context.Context, in *endpoint.DescribeEndpointRequest) (*endpoint.Endpoint, error) {
+ query := datasource.DBFromCtx(ctx)
+
+ ins := &endpoint.Endpoint{}
+ if err := query.First(ins).Error; err != nil {
+ if err == gorm.ErrRecordNotFound {
+ return nil, exception.NewNotFound("endpoint %d not found", in.Id)
+ }
+ return nil, err
+ }
+
+ return ins, nil
+}
diff --git a/devcloud/mcenter/apps/endpoint/impl/impl.go b/devcloud/mcenter/apps/endpoint/impl/impl.go
new file mode 100644
index 0000000..2882354
--- /dev/null
+++ b/devcloud/mcenter/apps/endpoint/impl/impl.go
@@ -0,0 +1,34 @@
+package impl
+
+import (
+ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint"
+ "github.com/infraboard/mcube/v2/ioc"
+ "github.com/infraboard/mcube/v2/ioc/config/datasource"
+)
+
+func init() {
+ ioc.Controller().Registry(&EndpointServiceImpl{})
+}
+
+var _ endpoint.Service = (*EndpointServiceImpl)(nil)
+
+// 他是user service 服务的控制器
+type EndpointServiceImpl struct {
+ ioc.ObjectImpl
+}
+
+func (i *EndpointServiceImpl) Init() error {
+ // 自动创建表
+ if datasource.Get().AutoMigrate {
+ err := datasource.DB().AutoMigrate(&endpoint.Endpoint{})
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// 定义托管到Ioc里面的名称
+func (i *EndpointServiceImpl) Name() string {
+ return endpoint.APP_NAME
+}
diff --git a/devcloud/mcenter/apps/endpoint/interface.go b/devcloud/mcenter/apps/endpoint/interface.go
new file mode 100644
index 0000000..a164bb8
--- /dev/null
+++ b/devcloud/mcenter/apps/endpoint/interface.go
@@ -0,0 +1,77 @@
+package endpoint
+
+import (
+ "context"
+
+ "slices"
+
+ "github.com/infraboard/mcube/v2/ioc"
+ "github.com/infraboard/mcube/v2/ioc/config/validator"
+ "github.com/infraboard/mcube/v2/types"
+ "github.com/infraboard/modules/iam/apps"
+)
+
+const (
+ APP_NAME = "endpoint"
+)
+
+func GetService() Service {
+ return ioc.Controller().Get(APP_NAME).(Service)
+}
+
+type Service interface {
+ // 注册API接口
+ RegistryEndpoint(context.Context, *RegistryEndpointRequest) (*types.Set[*Endpoint], error)
+ // 查询API接口列表
+ QueryEndpoint(context.Context, *QueryEndpointRequest) (*types.Set[*Endpoint], error)
+ // 查询API接口详情
+ DescribeEndpoint(context.Context, *DescribeEndpointRequest) (*Endpoint, error)
+}
+
+func NewQueryEndpointRequest() *QueryEndpointRequest {
+ return &QueryEndpointRequest{}
+}
+
+type QueryEndpointRequest struct {
+ Services []string `form:"services" json:"serivces"`
+}
+
+func (r *QueryEndpointRequest) WithService(services ...string) *QueryEndpointRequest {
+ for _, service := range services {
+ if !slices.Contains(r.Services, service) {
+ r.Services = append(r.Services, services...)
+ }
+ }
+ return r
+}
+
+func (r *QueryEndpointRequest) IsMatchAllService() bool {
+ return slices.Contains(r.Services, "*")
+}
+
+func NewDescribeEndpointRequest() *DescribeEndpointRequest {
+ return &DescribeEndpointRequest{}
+}
+
+type DescribeEndpointRequest struct {
+ apps.GetRequest
+}
+
+func NewRegistryEndpointRequest() *RegistryEndpointRequest {
+ return &RegistryEndpointRequest{
+ Items: []*RouteEntry{},
+ }
+}
+
+type RegistryEndpointRequest struct {
+ Items []*RouteEntry `json:"items"`
+}
+
+func (r *RegistryEndpointRequest) AddItem(items ...*RouteEntry) *RegistryEndpointRequest {
+ r.Items = append(r.Items, items...)
+ return r
+}
+
+func (r *RegistryEndpointRequest) Validate() error {
+ return validator.Validate(r)
+}
diff --git a/devcloud/mcenter/apps/endpoint/model.go b/devcloud/mcenter/apps/endpoint/model.go
index ed23be0..fbbd2c2 100644
--- a/devcloud/mcenter/apps/endpoint/model.go
+++ b/devcloud/mcenter/apps/endpoint/model.go
@@ -238,8 +238,10 @@ func NewEntryFromRestRoute(route restful.Route) *RouteEntry {
}
func NewEntryFromRestfulContainer(c *restful.Container) (entries []*RouteEntry) {
+ // 获取当前Container里面所有的 WebService
wss := c.RegisteredWebServices()
for i := range wss {
+ // 获取WebService下的路由条目
for _, route := range wss[i].Routes() {
es := NewEntryFromRestRoute(route)
entries = append(entries, es)
diff --git a/devcloud/mcenter/apps/registry.go b/devcloud/mcenter/apps/registry.go
index 061cb54..cf9cd5d 100644
--- a/devcloud/mcenter/apps/registry.go
+++ b/devcloud/mcenter/apps/registry.go
@@ -7,6 +7,8 @@ import (
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/token/api"
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/token/impl"
+ _ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint/impl"
+
// 颁发器
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/token/issuers"
// 鉴权中间件
diff --git a/devcloud/mcenter/apps/user/api/api.go b/devcloud/mcenter/apps/user/api/api.go
index a2bac75..b45cd97 100644
--- a/devcloud/mcenter/apps/user/api/api.go
+++ b/devcloud/mcenter/apps/user/api/api.go
@@ -37,6 +37,8 @@ func (h *UserRestfulApiHandler) Init() error {
// 这个开关怎么生效
// 中间件需求读取接口的描述信息,来决定是否需要认证
Metadata(permission.Auth(true)).
+ Metadata(permission.Resource("user")).
+ Metadata(permission.Action("list")).
Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")).
Param(restful.QueryParameter("page_number", "页码").DataType("integer")).
Writes(Set{}).
diff --git a/devcloud/mcenter/apps/user/design.drawio b/devcloud/mcenter/apps/user/design.drawio
index 1cdf92e..a76492d 100644
--- a/devcloud/mcenter/apps/user/design.drawio
+++ b/devcloud/mcenter/apps/user/design.drawio
@@ -43,7 +43,7 @@
-
+
diff --git a/devcloud/mcenter/permission/endpoint.go b/devcloud/mcenter/permission/endpoint.go
new file mode 100644
index 0000000..d258369
--- /dev/null
+++ b/devcloud/mcenter/permission/endpoint.go
@@ -0,0 +1,49 @@
+package permission
+
+import (
+ "context"
+
+ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint"
+ "github.com/infraboard/mcube/v2/ioc"
+ "github.com/infraboard/mcube/v2/ioc/config/gorestful"
+ "github.com/infraboard/mcube/v2/ioc/config/log"
+ "github.com/rs/zerolog"
+)
+
+func init() {
+ ioc.Api().Registry(&ApiRegister{})
+}
+
+func GetApiRegister() *ApiRegister {
+ return ioc.Api().Get("api_register").(*ApiRegister)
+}
+
+// 接口注册模块: 扫描当前GoResuful Container下所有路径,并完成注册
+type ApiRegister struct {
+ ioc.ObjectImpl
+
+ log *zerolog.Logger
+}
+
+func (c *ApiRegister) Name() string {
+ return "api_register"
+}
+
+// 这个Init一定要放到所有的路由都添加完成后进行
+func (i *ApiRegister) Priority() int {
+ return -100
+}
+
+func (a *ApiRegister) Init() error {
+ a.log = log.Sub(a.Name())
+ // 注册认证中间件
+ entries := endpoint.NewEntryFromRestfulContainer(gorestful.RootRouter())
+ req := endpoint.NewRegistryEndpointRequest()
+ req.AddItem(entries...)
+ set, err := endpoint.GetService().RegistryEndpoint(context.Background(), req)
+ if err != nil {
+ return err
+ }
+ a.log.Info().Msgf("registry endpoinst: %s", set.Items)
+ return nil
+}