补充应用授权

This commit is contained in:
yumaojun03 2025-06-29 15:26:49 +08:00
parent 1b27d97f2a
commit c76c8b1100
19 changed files with 224 additions and 53 deletions

View File

@ -5,7 +5,7 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "mcenter api server", "name": "devcloud api server",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",

View File

@ -11,8 +11,8 @@
database = "devcloud_go18" database = "devcloud_go18"
username = "root" username = "root"
password = "123456" password = "123456"
auto_migrate = true auto_migrate = false
debug = true debug = false
[mongo] [mongo]
endpoints = ["127.0.0.1:27017"] endpoints = ["127.0.0.1:27017"]

View File

@ -5,9 +5,12 @@ import (
// mcenter 业务对象 // mcenter 业务对象
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps" _ "122.51.31.227/go-course/go18/devcloud/mcenter/apps"
// audit 业务对象 // audit 业务对象
_ "122.51.31.227/go-course/go18/devcloud/audit/apps" _ "122.51.31.227/go-course/go18/devcloud/audit/apps"
// mpaas 应用发布 // mpaas 应用发布
_ "122.51.31.227/go-course/go18/devcloud/mpaas/apps"
// 非功能性模块 // 非功能性模块
_ "github.com/infraboard/mcube/v2/ioc/apps/apidoc/restful" _ "github.com/infraboard/mcube/v2/ioc/apps/apidoc/restful"

View File

@ -2,8 +2,8 @@ package impl
import ( import (
"context" "context"
"fmt"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace" "122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/policy" "122.51.31.227/go-course/go18/devcloud/mcenter/apps/policy"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/role" "122.51.31.227/go-course/go18/devcloud/mcenter/apps/role"
@ -36,8 +36,8 @@ func (i *PolicyServiceImpl) QueryNamespace(ctx context.Context, in *policy.Query
// 查询用户可以访问的Api接口 // 查询用户可以访问的Api接口
// 找到用户可以访问的角色列表然后在找出角色对应的Api访问权限 // 找到用户可以访问的角色列表然后在找出角色对应的Api访问权限
func (i *PolicyServiceImpl) QueryEndpoint(ctx context.Context, in *policy.QueryEndpointRequest) (*types.Set[*endpoint.Endpoint], error) { func (i *PolicyServiceImpl) QueryEndpoint(ctx context.Context, in *policy.QueryEndpointRequest) (*policy.QueryEndpointResponse, error) {
set := types.New[*endpoint.Endpoint]() resp := policy.NewQueryEndpointResponse()
policies, err := i.QueryPolicy(ctx, policies, err := i.QueryPolicy(ctx,
policy.NewQueryPolicyRequest(). policy.NewQueryPolicyRequest().
SetSkipPage(true). SetSkipPage(true).
@ -49,19 +49,25 @@ func (i *PolicyServiceImpl) QueryEndpoint(ctx context.Context, in *policy.QueryE
return nil, err return nil, err
} }
roleReq := role.NewQueryMatchedEndpointRequest() if policies.Len() > 1 {
policies.ForEach(func(t *policy.Policy) { return nil, fmt.Errorf("同一个空间下, 一个用户有多条[%d]授权", policies.Len())
roleReq.Add(t.RoleId...) }
})
p := policies.First()
roleReq := role.NewQueryMatchedEndpointRequest()
roleReq.Add(p.RoleId...)
// p.ResourceScope
resp.ResourceScope = p.ResourceScope
if policies.Len() > 0 { if policies.Len() > 0 {
set, err = role.GetService().QueryMatchedEndpoint(ctx, roleReq) set, err := role.GetService().QueryMatchedEndpoint(ctx, roleReq)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp.Items = set.Items
} }
return set, nil return resp, nil
} }
// 校验Api接口权限 // 校验Api接口权限
@ -69,7 +75,7 @@ func (i *PolicyServiceImpl) ValidateEndpointPermission(ctx context.Context, in *
resp := policy.NewValidateEndpointPermissionResponse(*in) resp := policy.NewValidateEndpointPermissionResponse(*in)
// 空间Owner有所有权限 // 空间Owner有所有权限
ns, err := namespace.GetService().DescribeNamespace(ctx, namespace.NewDescribeNamespaceRequest().SetNamespaceId(in.NamespaceId)) ns, err := namespace.GetService().DescribeNamespace(ctx, namespace.NewDescribeNamespaceRequest().SetNamespaceId(in.GetNamespaceId()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -81,15 +87,20 @@ func (i *PolicyServiceImpl) ValidateEndpointPermission(ctx context.Context, in *
// 非空间管理员需要独立鉴权, 查询用户可以访问的API列表 // 非空间管理员需要独立鉴权, 查询用户可以访问的API列表
endpointReq := policy.NewQueryEndpointRequest() endpointReq := policy.NewQueryEndpointRequest()
endpointReq.UserId = in.UserId endpointReq.UserId = in.UserId
endpointReq.NamespaceId = in.NamespaceId endpointReq.NamespaceId = in.GetNamespaceId()
endpointSet, err := i.QueryEndpoint(ctx, endpointReq) endpointSet, err := i.QueryEndpoint(ctx, endpointReq)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// 补充Api访问的scope
resp.ResourceScope = endpointSet.ResourceScope
for _, item := range endpointSet.Items { for _, item := range endpointSet.Items {
if item.IsMatched(in.Service, in.Method, in.Path) { if item.IsMatched(in.Service, in.Method, in.Path) {
resp.HasPermission = true resp.HasPermission = true
resp.Endpoint = item resp.Endpoint = item
break break
} }
} }

View File

@ -8,7 +8,7 @@ import (
func TestQueryNamespace(t *testing.T) { func TestQueryNamespace(t *testing.T) {
req := policy.NewQueryNamespaceRequest() req := policy.NewQueryNamespaceRequest()
req.UserId = 1 req.UserId = 2
set, err := impl.QueryNamespace(ctx, req) set, err := impl.QueryNamespace(ctx, req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -29,8 +29,8 @@ func TestQueryEndpoint(t *testing.T) {
func TestValidateEndpointPermission(t *testing.T) { func TestValidateEndpointPermission(t *testing.T) {
req := policy.NewValidateEndpointPermissionRequest() req := policy.NewValidateEndpointPermissionRequest()
req.UserId = 1 req.UserId = 3
req.NamespaceId = 1 req.SetNamespaceId(1)
req.Service = "devcloud" req.Service = "devcloud"
req.Method = "GET" req.Method = "GET"
req.Path = "/api/devcloud/v1/users/" req.Path = "/api/devcloud/v1/users/"

View File

@ -20,9 +20,14 @@ func TestQueryPolicy(t *testing.T) {
func TestCreatePolicy(t *testing.T) { func TestCreatePolicy(t *testing.T) {
req := policy.NewCreatePolicyRequest() req := policy.NewCreatePolicyRequest()
// guest
req.UserId = 2 req.UserId = 2
req.RoleId = []uint64{1} // 开发
req.RoleId = []uint64{3}
// default
req.SetNamespaceId(1) req.SetNamespaceId(1)
// 开发小组1的资源
req.SetScope("team", []string{"dev01"})
set, err := impl.CreatePolicy(ctx, req) set, err := impl.CreatePolicy(ctx, req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -132,17 +132,28 @@ type PermissionService interface {
// 查询用户可以访问的菜单 // 查询用户可以访问的菜单
QueryMenu(context.Context, *QueryMenuRequest) (*types.Set[*view.Menu], error) QueryMenu(context.Context, *QueryMenuRequest) (*types.Set[*view.Menu], error)
// 查询用户可以访问的Api接口 // 查询用户可以访问的Api接口
QueryEndpoint(context.Context, *QueryEndpointRequest) (*types.Set[*endpoint.Endpoint], error) QueryEndpoint(context.Context, *QueryEndpointRequest) (*QueryEndpointResponse, error)
// 校验页面权限 // 校验页面权限
ValidatePagePermission(context.Context, *ValidatePagePermissionRequest) (*ValidatePagePermissionResponse, error) ValidatePagePermission(context.Context, *ValidatePagePermissionRequest) (*ValidatePagePermissionResponse, error)
// 校验接口权限 // 校验接口权限
ValidateEndpointPermission(context.Context, *ValidateEndpointPermissionRequest) (*ValidateEndpointPermissionResponse, error) ValidateEndpointPermission(context.Context, *ValidateEndpointPermissionRequest) (*ValidateEndpointPermissionResponse, error)
} }
func NewQueryEndpointResponse() *QueryEndpointResponse {
return &QueryEndpointResponse{
Items: []*endpoint.Endpoint{},
}
}
type QueryEndpointResponse struct {
ResourceScope
Items []*endpoint.Endpoint
}
type ValidatePagePermissionRequest struct { type ValidatePagePermissionRequest struct {
UserId uint64 `json:"user_id" form:"user_id"` UserId uint64 `json:"user_id" form:"user_id"`
NamespaceId uint64 `json:"namespace_id" form:"namespace_id"`
Path string `json:"path" form:"path"` Path string `json:"path" form:"path"`
ResourceScope
} }
func NewValidatePagePermissionResponse(req ValidatePagePermissionRequest) *ValidatePagePermissionResponse { func NewValidatePagePermissionResponse(req ValidatePagePermissionRequest) *ValidatePagePermissionResponse {
@ -163,10 +174,10 @@ func NewValidateEndpointPermissionRequest() *ValidateEndpointPermissionRequest {
type ValidateEndpointPermissionRequest struct { type ValidateEndpointPermissionRequest struct {
UserId uint64 `json:"user_id" form:"user_id"` UserId uint64 `json:"user_id" form:"user_id"`
NamespaceId uint64 `json:"namespace_id" form:"namespace_id"`
Service string `json:"service" form:"service"` Service string `json:"service" form:"service"`
Path string `json:"path" form:"path"` Path string `json:"path" form:"path"`
Method string `json:"method" form:"method"` Method string `json:"method" form:"method"`
ResourceScope
} }
func NewValidateEndpointPermissionResponse(req ValidateEndpointPermissionRequest) *ValidateEndpointPermissionResponse { func NewValidateEndpointPermissionResponse(req ValidateEndpointPermissionRequest) *ValidateEndpointPermissionResponse {

View File

@ -82,6 +82,31 @@ type ResourceScope struct {
Scope map[string][]string `json:"scope" bson:"scope" gorm:"column:scope;serializer:json;type:json" description:"数据访问的范围" optional:"true"` Scope map[string][]string `json:"scope" bson:"scope" gorm:"column:scope;serializer:json;type:json" description:"数据访问的范围" optional:"true"`
} }
func (r ResourceScope) String() string {
return pretty.ToJSON(r)
}
func (r *ResourceScope) BuildMySQLPrefixBlob() {
for k := range r.Scope {
for i := range r.Scope[k] {
if !strings.HasSuffix(r.Scope[k][i], "%") {
r.Scope[k][i] += "%"
}
}
}
}
func (r *ResourceScope) SetNamespaceId(v uint64) {
r.NamespaceId = &v
}
func (r *ResourceScope) GetNamespaceId() uint64 {
if r.NamespaceId == nil {
return 0
}
return *r.NamespaceId
}
func (l *ResourceScope) SetScope(key string, value []string) { func (l *ResourceScope) SetScope(key string, value []string) {
if l.Scope == nil { if l.Scope == nil {
l.Scope = map[string][]string{} l.Scope = map[string][]string{}
@ -91,7 +116,7 @@ func (l *ResourceScope) SetScope(key string, value []string) {
func (r ResourceScope) GormResourceFilter(query *gorm.DB) *gorm.DB { func (r ResourceScope) GormResourceFilter(query *gorm.DB) *gorm.DB {
if r.NamespaceId != nil { if r.NamespaceId != nil {
query = query.Where("namespace = ?", r.NamespaceId) query = query.Where("namespace_id = ?", r.NamespaceId)
} }
for key, values := range r.Scope { for key, values := range r.Scope {
@ -144,6 +169,10 @@ type ResourceLabel struct {
Label map[string]string `json:"label" bson:"label" gorm:"column:label;serializer:json;type:json" description:"数据访问的范围" optional:"true"` Label map[string]string `json:"label" bson:"label" gorm:"column:label;serializer:json;type:json" description:"数据访问的范围" optional:"true"`
} }
func (l *ResourceLabel) SetNamespaceId(v uint64) {
l.NamespaceId = &v
}
func (l *ResourceLabel) SetLabel(key, value string) { func (l *ResourceLabel) SetLabel(key, value string) {
if l.Label == nil { if l.Label == nil {
l.Label = map[string]string{} l.Label = map[string]string{}

View File

@ -8,7 +8,7 @@ import (
func TestQueryApiPermission(t *testing.T) { func TestQueryApiPermission(t *testing.T) {
req := role.NewQueryApiPermissionRequest() req := role.NewQueryApiPermissionRequest()
req.AddRoleId(2) req.AddRoleId(3)
set, err := impl.QueryApiPermission(ctx, req) set, err := impl.QueryApiPermission(ctx, req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -17,8 +17,11 @@ func TestQueryApiPermission(t *testing.T) {
} }
func TestAddApiPermission(t *testing.T) { func TestAddApiPermission(t *testing.T) {
req := role.NewAddApiPermissionRequest(1) req := role.NewAddApiPermissionRequest(3)
req.Add(role.NewResourceActionApiPermissionSpec("devcloud", "user", "list")) req.Add(
role.NewResourceActionApiPermissionSpec("devcloud", "user", "list"),
// role.NewResourceActionApiPermissionSpec("devcloud", "application", "list"),
)
set, err := impl.AddApiPermission(ctx, req) set, err := impl.AddApiPermission(ctx, req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -28,7 +31,7 @@ func TestAddApiPermission(t *testing.T) {
func TestQueryMatchedEndpoint(t *testing.T) { func TestQueryMatchedEndpoint(t *testing.T) {
req := role.NewQueryMatchedEndpointRequest() req := role.NewQueryMatchedEndpointRequest()
req.Add(1) req.Add(3)
set, err := impl.QueryMatchedEndpoint(ctx, req) set, err := impl.QueryMatchedEndpoint(ctx, req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -49,8 +49,8 @@ func (i *TokenServiceImpl) IssueToken(ctx context.Context, in *token.IssueTokenR
} }
} }
if tk.NamespaceId == 0 { if tk.NamespaceId == nil {
tk.NamespaceId = 1 tk.SetNamespaceId(1)
} }
// 保持Token // 保持Token

View File

@ -8,6 +8,7 @@ import (
"strings" "strings"
"time" "time"
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/policy"
"github.com/infraboard/mcube/v2/exception" "github.com/infraboard/mcube/v2/exception"
"github.com/infraboard/mcube/v2/tools/pretty" "github.com/infraboard/mcube/v2/tools/pretty"
) )
@ -56,7 +57,6 @@ func NewToken() *Token {
IssueAt: time.Now(), IssueAt: time.Now(),
Status: NewStatus(), Status: NewStatus(),
Extras: map[string]string{}, Extras: map[string]string{},
Scope: map[string]string{},
} }
return tk return tk
@ -77,12 +77,14 @@ type Token struct {
UserName string `json:"user_name" gorm:"column:user_name;type:varchar(100);not null;index" description:"持有该Token的用户名称"` UserName string `json:"user_name" gorm:"column:user_name;type:varchar(100);not null;index" description:"持有该Token的用户名称"`
// 是不是管理员 // 是不是管理员
IsAdmin bool `json:"is_admin" gorm:"column:is_admin;type:tinyint(1)" description:"是不是管理员"` IsAdmin bool `json:"is_admin" gorm:"column:is_admin;type:tinyint(1)" description:"是不是管理员"`
// 令牌生效空间Id
NamespaceId uint64 `json:"namespace_id" gorm:"column:namespace_id;type:uint;index" description:"令牌所属空间Id"` // 令牌生效空间Ids
policy.ResourceScope
// NamespaceId uint64 `json:"namespace_id" gorm:"column:namespace_id;type:uint;index" description:"令牌所属空间Id"`
// 令牌生效空间名称 // 令牌生效空间名称
NamespaceName string `json:"namespace_name" gorm:"column:namespace_name;type:varchar(100);index" description:"令牌所属空间"` NamespaceName string `json:"namespace_name" gorm:"column:namespace_name;type:varchar(100);index" description:"令牌所属空间"`
// 访问范围定义, 鉴权完成后补充 // // 访问范围定义, 鉴权完成后补充
Scope map[string]string `json:"scope" gorm:"column:scope;type:varchar(100);serializer:json" description:"令牌访问范围定义"` // Scope map[string][]string `json:"scope" gorm:"column:scope;type:varchar(100);serializer:json" description:"令牌访问范围定义"`
// 颁发给用户的访问令牌(用户需要携带Token来访问接口) // 颁发给用户的访问令牌(用户需要携带Token来访问接口)
AccessToken string `json:"access_token" gorm:"column:access_token;type:varchar(100);not null;uniqueIndex" description:"访问令牌"` AccessToken string `json:"access_token" gorm:"column:access_token;type:varchar(100);not null;uniqueIndex" description:"访问令牌"`
// 访问令牌过期时间 // 访问令牌过期时间
@ -105,6 +107,10 @@ func (t *Token) TableName() string {
return "tokens" return "tokens"
} }
func (r *Token) String() string {
return pretty.ToJSON(r)
}
// 判断访问令牌是否过期,没设置代表用不过期 // 判断访问令牌是否过期,没设置代表用不过期
func (t *Token) IsAccessTokenExpired() error { func (t *Token) IsAccessTokenExpired() error {
if t.AccessTokenExpiredAt != nil { if t.AccessTokenExpiredAt != nil {
@ -158,10 +164,6 @@ func (t *Token) SetRefreshTokenExpiredAt(v time.Time) {
t.RefreshTokenExpiredAt = &v t.RefreshTokenExpiredAt = &v
} }
func (t *Token) String() string {
return pretty.ToJSON(t)
}
func (t *Token) SetIssuer(issuer string) *Token { func (t *Token) SetIssuer(issuer string) *Token {
t.Issuer = issuer t.Issuer = issuer
return t return t

View File

@ -92,6 +92,14 @@ func (c *Checker) Check(r *restful.Request, w *restful.Response, next *restful.F
response.Failed(w, err) response.Failed(w, err)
return return
} }
// 如果校验成功,需要把 用户的身份信息,放到请求的上下文中,方便后面的逻辑获取
// context.WithValue 来往ctx 添加 value
// key: value, value token对象
ctx := context.WithValue(r.Request.Context(), token.CTX_TOKEN_KEY, tk)
// ctx 生成一个新的,继续往下传递
r.Request = r.Request.WithContext(ctx)
} }
// 请求处理 // 请求处理
@ -111,13 +119,6 @@ func (c *Checker) CheckToken(r *restful.Request) (*token.Token, error) {
return nil, err return nil, err
} }
// 如果校验成功,需要把 用户的身份信息,放到请求的上下文中,方便后面的逻辑获取
// context.WithValue 来往ctx 添加 value
// key: value, value token对象
ctx := context.WithValue(r.Request.Context(), token.CTX_TOKEN_KEY, tk)
// ctx 生成一个新的,继续往下传递
r.Request = r.Request.WithContext(ctx)
return tk, nil return tk, nil
} }
@ -131,7 +132,7 @@ func (c *Checker) CheckPolicy(r *restful.Request, tk *token.Token, route *endpoi
if route.HasRequiredRole() { if route.HasRequiredRole() {
set, err := c.policy.QueryPolicy(r.Request.Context(), set, err := c.policy.QueryPolicy(r.Request.Context(),
policy.NewQueryPolicyRequest(). policy.NewQueryPolicyRequest().
SetNamespaceId(tk.NamespaceId). SetNamespaceId(tk.GetNamespaceId()).
SetUserId(tk.UserId). SetUserId(tk.UserId).
SetExpired(false). SetExpired(false).
SetEnabled(true). SetEnabled(true).
@ -145,6 +146,9 @@ func (c *Checker) CheckPolicy(r *restful.Request, tk *token.Token, route *endpoi
p := set.Items[i] p := set.Items[i]
if route.IsRequireRole(p.Role.Name) { if route.IsRequireRole(p.Role.Name) {
hasPerm = true hasPerm = true
// 把这个scope传递下去
tk.Scope = p.Scope
break break
} }
} }
@ -157,7 +161,7 @@ func (c *Checker) CheckPolicy(r *restful.Request, tk *token.Token, route *endpoi
if route.RequiredPerm { if route.RequiredPerm {
validateReq := policy.NewValidateEndpointPermissionRequest() validateReq := policy.NewValidateEndpointPermissionRequest()
validateReq.UserId = tk.UserId validateReq.UserId = tk.UserId
validateReq.NamespaceId = tk.NamespaceId validateReq.ResourceScope = tk.ResourceScope
validateReq.Service = application.Get().GetAppName() validateReq.Service = application.Get().GetAppName()
validateReq.Method = route.Method validateReq.Method = route.Method
validateReq.Path = route.Path validateReq.Path = route.Path
@ -168,6 +172,9 @@ func (c *Checker) CheckPolicy(r *restful.Request, tk *token.Token, route *endpoi
if !resp.HasPermission { if !resp.HasPermission {
return exception.NewPermissionDeny("无权限访问") return exception.NewPermissionDeny("无权限访问")
} }
tk.ResourceScope = resp.ResourceScope
tk.BuildMySQLPrefixBlob()
} }
return nil return nil

View File

@ -0,0 +1,58 @@
package api
import (
"122.51.31.227/go-course/go18/devcloud/audit/audit"
"122.51.31.227/go-course/go18/devcloud/mcenter/permission"
"122.51.31.227/go-course/go18/devcloud/mpaas/apps/application"
"github.com/infraboard/mcube/v2/ioc"
"github.com/infraboard/mcube/v2/ioc/config/gorestful"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
"github.com/emicklei/go-restful/v3"
)
func init() {
ioc.Api().Registry(&UserRestfulApiHandler{})
}
type UserRestfulApiHandler struct {
ioc.ObjectImpl
// 依赖控制器
svc application.Service
}
func (h *UserRestfulApiHandler) Name() string {
return "applications"
}
func (h *UserRestfulApiHandler) Init() error {
h.svc = application.GetService()
tags := []string{"应用管理"}
ws := gorestful.ObjectRouter(h)
// required_auth=true/false
ws.Route(ws.GET("").To(h.QueryApplication).
Doc("应用列表查询").
Metadata(restfulspec.KeyOpenAPITags, tags).
// 这个开关怎么生效
// 中间件需求读取接口的描述信息,来决定是否需要认证
Metadata(permission.Auth(true)).
Metadata(permission.Permission(true)).
Metadata(permission.Resource("application")).
Metadata(permission.Action("list")).
Metadata(audit.Enable(true)).
Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")).
Param(restful.QueryParameter("page_number", "页码").DataType("integer")).
Writes(Set{}).
Returns(200, "OK", Set{}))
return nil
}
// *types.Set[*User]
// 返回的泛型, API Doc这个工具 不支持泛型
type Set struct {
Total int64 `json:"total"`
Items []application.Application `json:"items"`
}

View File

@ -0,0 +1,31 @@
package api
import (
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/token"
"122.51.31.227/go-course/go18/devcloud/mpaas/apps/application"
"github.com/emicklei/go-restful/v3"
"github.com/gin-gonic/gin/binding"
"github.com/infraboard/mcube/v2/http/restful/response"
"github.com/infraboard/mcube/v2/ioc/config/log"
)
func (h *UserRestfulApiHandler) QueryApplication(r *restful.Request, w *restful.Response) {
req := application.NewQueryApplicationRequest()
if err := binding.Query.Bind(r.Request, &req.QueryApplicationRequestSpec); err != nil {
response.Failed(w, err)
return
}
// 过滤条件在认证完成后的上下文中
tk := token.GetTokenFromCtx(r.Request.Context())
req.ResourceScope = tk.ResourceScope
log.L().Debug().Msgf("resource scope: %s", tk.ResourceScope)
set, err := h.svc.QueryApplication(r.Request.Context(), req)
if err != nil {
response.Failed(w, err)
return
}
response.Success(w, set)
}

View File

@ -29,6 +29,7 @@ func (i *ApplicationServiceImpl) CreateApplication(ctx context.Context, in *appl
func (i *ApplicationServiceImpl) QueryApplication(ctx context.Context, in *application.QueryApplicationRequest) (*types.Set[*application.Application], error) { func (i *ApplicationServiceImpl) QueryApplication(ctx context.Context, in *application.QueryApplicationRequest) (*types.Set[*application.Application], error) {
set := types.New[*application.Application]() set := types.New[*application.Application]()
i.log.Debug().Msgf("scope: %s", in.ResourceScope)
query := in.GormResourceFilter(datasource.DBFromCtx(ctx).Model(&application.Application{})) query := in.GormResourceFilter(datasource.DBFromCtx(ctx).Model(&application.Application{}))
if in.Id != "" { if in.Id != "" {
query = query.Where("id = ?", in.Id) query = query.Where("id = ?", in.Id)

View File

@ -14,6 +14,7 @@ func TestCreateApplication(t *testing.T) {
req.CodeRepository = application.CodeRepository{ req.CodeRepository = application.CodeRepository{
SshUrl: "git@122.51.31.227:go-course/go18.git", SshUrl: "git@122.51.31.227:go-course/go18.git",
} }
req.SetNamespaceId(1)
req.SetLabel("team", "dev01.web_developer") req.SetLabel("team", "dev01.web_developer")
ins, err := svc.CreateApplication(ctx, req) ins, err := svc.CreateApplication(ctx, req)
if err != nil { if err != nil {
@ -26,7 +27,8 @@ func TestCreateApplication(t *testing.T) {
func TestQueryApplication(t *testing.T) { func TestQueryApplication(t *testing.T) {
req := application.NewQueryApplicationRequest() req := application.NewQueryApplicationRequest()
// dev01.% // dev01.%
req.SetScope("team", []string{"%"}) // req.SetNamespaceId(1)
req.SetScope("team", []string{"dev01%"})
// req.SetScope("env", []string{"prod"}) // req.SetScope("env", []string{"prod"})
ins, err := svc.QueryApplication(ctx, req) ins, err := svc.QueryApplication(ctx, req)
if err != nil { if err != nil {

View File

@ -4,6 +4,8 @@ import (
"122.51.31.227/go-course/go18/devcloud/mpaas/apps/application" "122.51.31.227/go-course/go18/devcloud/mpaas/apps/application"
"github.com/infraboard/mcube/v2/ioc" "github.com/infraboard/mcube/v2/ioc"
"github.com/infraboard/mcube/v2/ioc/config/datasource" "github.com/infraboard/mcube/v2/ioc/config/datasource"
"github.com/infraboard/mcube/v2/ioc/config/log"
"github.com/rs/zerolog"
) )
func init() { func init() {
@ -14,9 +16,13 @@ var _ application.Service = (*ApplicationServiceImpl)(nil)
type ApplicationServiceImpl struct { type ApplicationServiceImpl struct {
ioc.ObjectImpl ioc.ObjectImpl
log *zerolog.Logger
} }
func (i *ApplicationServiceImpl) Init() error { func (i *ApplicationServiceImpl) Init() error {
i.log = log.Sub(i.Name())
if datasource.Get().AutoMigrate { if datasource.Get().AutoMigrate {
err := datasource.DB().AutoMigrate(&application.Application{}) err := datasource.DB().AutoMigrate(&application.Application{})
if err != nil { if err != nil {

View File

@ -1,5 +1,6 @@
package apps package apps
import ( import (
_ "122.51.31.227/go-course/go18/devcloud/mpaas/apps/application/api"
_ "122.51.31.227/go-course/go18/devcloud/mpaas/apps/application/impl" _ "122.51.31.227/go-course/go18/devcloud/mpaas/apps/application/impl"
) )

View File

@ -7,6 +7,7 @@ import (
// 要注册哪些对象, Book, Comment // 要注册哪些对象, Book, Comment
// 加载的业务对象 // 加载的业务对象
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps"
_ "122.51.31.227/go-course/go18/devcloud/mpaas/apps" _ "122.51.31.227/go-course/go18/devcloud/mpaas/apps"
) )