udpate
This commit is contained in:
parent
298cadf2e2
commit
e1774f973a
17
devcloud/.vscode/launch.json
vendored
Normal file
17
devcloud/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
// 使用 IntelliSense 了解相关属性。
|
||||||
|
// 悬停以查看现有属性的描述。
|
||||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "mcenter api server",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/main.go",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"args": ["start","-f","${workspaceFolder}/etc/application.toml"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
47
devcloud/Makefile
Normal file
47
devcloud/Makefile
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
PKG := "122.51.31.227/go-course/go18/devcloud"
|
||||||
|
MOD_DIR := $(shell go env GOPATH)/pkg/mod
|
||||||
|
PKG_LIST := $(shell go list ${PKG}/... | grep -v /vendor/ | grep -v redis)
|
||||||
|
GO_FILES := $(shell find . -name '*.go' | grep -v /vendor/ | grep -v _test.go)
|
||||||
|
|
||||||
|
GIT_TAG := $()
|
||||||
|
BUILD_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
|
BUILD_COMMIT := ${shell git rev-parse HEAD}
|
||||||
|
BUILD_TIME := ${shell date '+%Y-%m-%d %H:%M:%S'}
|
||||||
|
BUILD_GO_VERSION := $(shell go version | grep -o 'go[0-9].[0-9].*')
|
||||||
|
VERSION_PATH := "github.com/infraboard/mcube/v2/ioc/config/application"
|
||||||
|
OUTPUT_NAME := "devcloud-api"
|
||||||
|
|
||||||
|
.PHONY: all dep lint vet test test-coverage build clean
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
dep: ## Get the dependencies
|
||||||
|
@go mod tidy
|
||||||
|
|
||||||
|
lint: ## Lint Golang files
|
||||||
|
@golint -set_exit_status ${PKG_LIST}
|
||||||
|
|
||||||
|
vet: ## Run go vet
|
||||||
|
@go vet ${PKG_LIST}
|
||||||
|
|
||||||
|
run: ## Run Devcloud
|
||||||
|
@go run main.go start
|
||||||
|
|
||||||
|
build: dep ## Build the binary file
|
||||||
|
@go build -a -o dist/${OUTPUT_NAME} -ldflags "-s -w" -ldflags "-X '${VERSION_PATH}.GIT_BRANCH=${BUILD_BRANCH}' -X '${VERSION_PATH}.GIT_COMMIT=${BUILD_COMMIT}' -X '${VERSION_PATH}.BUILD_TIME=${BUILD_TIME}' -X '${VERSION_PATH}.GO_VERSION=${BUILD_GO_VERSION}' -X '${VERSION_PATH}.GIT_TAG=${GIT_TAG}'" ${MAIN_FILE}
|
||||||
|
|
||||||
|
linux: dep ## Build the linux binary file
|
||||||
|
@GOOS=linux GOARCH=amd64 go build -a -o dist/${OUTPUT_NAME} -ldflags "-s -w" -ldflags "-X '${VERSION_PATH}.GIT_BRANCH=${BUILD_BRANCH}' -X '${VERSION_PATH}.GIT_COMMIT=${BUILD_COMMIT}' -X '${VERSION_PATH}.BUILD_TIME=${BUILD_TIME}' -X '${VERSION_PATH}.GO_VERSION=${BUILD_GO_VERSION}' -X '${VERSION_PATH}.GIT_TAG=${GIT_TAG}'" ${MAIN_FILE}
|
||||||
|
|
||||||
|
image: dep ## Build the docker image
|
||||||
|
docker build -t ${IMAGE_VERSION} -f Dockerfile .
|
||||||
|
|
||||||
|
test: ## Run unittests
|
||||||
|
@go test -short ${PKG_LIST}
|
||||||
|
|
||||||
|
test-coverage: ## Run tests with coverage
|
||||||
|
@go test -short -coverprofile cover.out -covermode=atomic ${PKG_LIST}
|
||||||
|
@cat cover.out >> coverage.txt
|
||||||
|
|
||||||
|
help: ## Display this help screen
|
||||||
|
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
@ -10,3 +10,4 @@ devcloud: 研发云, 给产研团队(技术团队), 产品经理, 项目经理,
|
|||||||
+ 发布中心(Dev/Test/Pre/Pro)CD: 发布, 应用维护, 部署集群的维护
|
+ 发布中心(Dev/Test/Pre/Pro)CD: 发布, 应用维护, 部署集群的维护
|
||||||
|
|
||||||
多业务模块组成, 渐进式微服务开发方式
|
多业务模块组成, 渐进式微服务开发方式
|
||||||
|
|
||||||
|
BIN
devcloud/dist/devcloud-api
vendored
Executable file
BIN
devcloud/dist/devcloud-api
vendored
Executable file
Binary file not shown.
@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/infraboard/mcube/v2/ioc/server/cmd"
|
"github.com/infraboard/mcube/v2/ioc/server/cmd"
|
||||||
|
|
||||||
// 加载的业务对象
|
// mcenter 业务对象
|
||||||
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps"
|
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps"
|
||||||
|
|
||||||
// 非功能性模块
|
// 非功能性模块
|
@ -18,7 +18,7 @@ func TestQueryNamespace(t *testing.T) {
|
|||||||
|
|
||||||
func TestQueryEndpoint(t *testing.T) {
|
func TestQueryEndpoint(t *testing.T) {
|
||||||
req := policy.NewQueryEndpointRequest()
|
req := policy.NewQueryEndpointRequest()
|
||||||
req.UserId = 1
|
req.UserId = 2
|
||||||
req.NamespaceId = 1
|
req.NamespaceId = 1
|
||||||
set, err := impl.QueryEndpoint(ctx, req)
|
set, err := impl.QueryEndpoint(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -36,6 +36,16 @@ func (i *PolicyServiceImpl) QueryPolicy(ctx context.Context, in *policy.QueryPol
|
|||||||
set := types.New[*policy.Policy]()
|
set := types.New[*policy.Policy]()
|
||||||
|
|
||||||
query := datasource.DBFromCtx(ctx).Model(&policy.Policy{}).Order("created_at desc")
|
query := datasource.DBFromCtx(ctx).Model(&policy.Policy{}).Order("created_at desc")
|
||||||
|
if in.UserId != nil {
|
||||||
|
query = query.Where("user_id = ?", in.UserId)
|
||||||
|
}
|
||||||
|
if in.NamespaceId != nil {
|
||||||
|
query = query.Where("namespace_id = ?", in.NamespaceId)
|
||||||
|
}
|
||||||
|
if in.Enabled != nil {
|
||||||
|
query = query.Where("enabled = ?", in.Enabled)
|
||||||
|
}
|
||||||
|
|
||||||
err := query.Count(&set.Total).Error
|
err := query.Count(&set.Total).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -21,7 +21,7 @@ func TestQueryPolicy(t *testing.T) {
|
|||||||
func TestCreatePolicy(t *testing.T) {
|
func TestCreatePolicy(t *testing.T) {
|
||||||
req := policy.NewCreatePolicyRequest()
|
req := policy.NewCreatePolicyRequest()
|
||||||
req.SetNamespaceId(1)
|
req.SetNamespaceId(1)
|
||||||
req.UserId = 1
|
req.UserId = 2
|
||||||
req.RoleId = 1
|
req.RoleId = 1
|
||||||
set, err := impl.CreatePolicy(ctx, req)
|
set, err := impl.CreatePolicy(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,6 +49,10 @@ func (i *TokenServiceImpl) IssueToken(ctx context.Context, in *token.IssueTokenR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tk.NamespaceId == 0 {
|
||||||
|
tk.NamespaceId = 1
|
||||||
|
}
|
||||||
|
|
||||||
// 保持Token
|
// 保持Token
|
||||||
if err := datasource.DBFromCtx(ctx).
|
if err := datasource.DBFromCtx(ctx).
|
||||||
Create(tk).
|
Create(tk).
|
||||||
|
@ -37,6 +37,7 @@ func (h *UserRestfulApiHandler) Init() error {
|
|||||||
// 这个开关怎么生效
|
// 这个开关怎么生效
|
||||||
// 中间件需求读取接口的描述信息,来决定是否需要认证
|
// 中间件需求读取接口的描述信息,来决定是否需要认证
|
||||||
Metadata(permission.Auth(true)).
|
Metadata(permission.Auth(true)).
|
||||||
|
Metadata(permission.Permission(true)).
|
||||||
Metadata(permission.Resource("user")).
|
Metadata(permission.Resource("user")).
|
||||||
Metadata(permission.Action("list")).
|
Metadata(permission.Action("list")).
|
||||||
Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")).
|
Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")).
|
||||||
|
@ -29,6 +29,7 @@ const (
|
|||||||
type TYPE int32
|
type TYPE int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// 普通用户
|
||||||
TYPE_SUB TYPE = 0
|
TYPE_SUB TYPE = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -4,16 +4,51 @@
|
|||||||
1. 路有装饰, 路有配置
|
1. 路有装饰, 路有配置
|
||||||
```go
|
```go
|
||||||
// required_auth=true/false
|
// required_auth=true/false
|
||||||
ws.Route(ws.GET("").To(h.QueryUser).
|
// required_auth=true/false
|
||||||
Doc("用户列表查询").
|
ws.Route(ws.GET("").To(h.QueryUser).
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
Doc("用户列表查询").
|
||||||
// 这个开关怎么生效
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
// 中间件需求读取接口的描述信息,来决定是否需要认证
|
// 这个开关怎么生效
|
||||||
Metadata(permission.Auth(true)).
|
// 中间件需求读取接口的描述信息,来决定是否需要认证
|
||||||
Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")).
|
Metadata(permission.Auth(true)).
|
||||||
Param(restful.QueryParameter("page_number", "页码").DataType("integer")).
|
Metadata(permission.Permission(true)).
|
||||||
Writes(Set{}).
|
Metadata(permission.Resource("user")).
|
||||||
Returns(200, "OK", Set{}))
|
Metadata(permission.Action("list")).
|
||||||
|
Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")).
|
||||||
|
Param(restful.QueryParameter("page_number", "页码").DataType("integer")).
|
||||||
|
Writes(Set{}).
|
||||||
|
Returns(200, "OK", Set{}))
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 加载鉴权处理逻辑(中间件)
|
2. 加载鉴权处理逻辑(中间件)
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 中间件的函数里面
|
||||||
|
func (c *Checker) Check(r *restful.Request, w *restful.Response, next *restful.FilterChain) {
|
||||||
|
// 请求处理前, 对接口进行保护
|
||||||
|
// 1. 知道用户当前访问的是哪个接口, 当前url 匹配到的路由是哪个
|
||||||
|
// SelectedRoute, 它可以返回当前URL适配哪个路有, RouteReader
|
||||||
|
// 封装了一个函数 来获取Meta信息 NewEntryFromRestRouteReader
|
||||||
|
route := endpoint.NewEntryFromRestRouteReader(r.SelectedRoute())
|
||||||
|
if route.RequiredAuth {
|
||||||
|
// 校验身份
|
||||||
|
tk, err := c.CheckToken(r)
|
||||||
|
if err != nil {
|
||||||
|
response.Failed(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验权限
|
||||||
|
if err := c.CheckPolicy(r, tk, route); err != nil {
|
||||||
|
response.Failed(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求处理
|
||||||
|
next.ProcessFilter(r, w)
|
||||||
|
|
||||||
|
// 请求处理后
|
||||||
|
}
|
||||||
|
```
|
@ -4,11 +4,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint"
|
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint"
|
||||||
|
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/policy"
|
||||||
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/token"
|
"122.51.31.227/go-course/go18/devcloud/mcenter/apps/token"
|
||||||
"github.com/emicklei/go-restful/v3"
|
"github.com/emicklei/go-restful/v3"
|
||||||
"github.com/infraboard/mcube/v2/exception"
|
"github.com/infraboard/mcube/v2/exception"
|
||||||
"github.com/infraboard/mcube/v2/http/restful/response"
|
"github.com/infraboard/mcube/v2/http/restful/response"
|
||||||
"github.com/infraboard/mcube/v2/ioc"
|
"github.com/infraboard/mcube/v2/ioc"
|
||||||
|
"github.com/infraboard/mcube/v2/ioc/config/application"
|
||||||
"github.com/infraboard/mcube/v2/ioc/config/gorestful"
|
"github.com/infraboard/mcube/v2/ioc/config/gorestful"
|
||||||
"github.com/infraboard/mcube/v2/ioc/config/log"
|
"github.com/infraboard/mcube/v2/ioc/config/log"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
@ -40,8 +42,8 @@ type Checker struct {
|
|||||||
ioc.ObjectImpl
|
ioc.ObjectImpl
|
||||||
log *zerolog.Logger
|
log *zerolog.Logger
|
||||||
|
|
||||||
token token.Service
|
token token.Service
|
||||||
// policy policy.Service
|
policy policy.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
// 中间件对象名称
|
// 中间件对象名称
|
||||||
@ -59,7 +61,7 @@ func (c *Checker) Priority() int {
|
|||||||
func (c *Checker) Init() error {
|
func (c *Checker) Init() error {
|
||||||
c.log = log.Sub(c.Name())
|
c.log = log.Sub(c.Name())
|
||||||
c.token = token.GetService()
|
c.token = token.GetService()
|
||||||
// c.policy = policy.GetService()
|
c.policy = policy.GetService()
|
||||||
|
|
||||||
// 注册认证中间件
|
// 注册认证中间件
|
||||||
gorestful.RootRouter().Filter(c.Check)
|
gorestful.RootRouter().Filter(c.Check)
|
||||||
@ -116,5 +118,53 @@ func (c *Checker) CheckToken(r *restful.Request) (*token.Token, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Checker) CheckPolicy(r *restful.Request, tk *token.Token, route *endpoint.RouteEntry) error {
|
func (c *Checker) CheckPolicy(r *restful.Request, tk *token.Token, route *endpoint.RouteEntry) error {
|
||||||
|
// 判断用户是否是超级管理员
|
||||||
|
if tk.IsAdmin {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色校验 @Required('admin', '')
|
||||||
|
if route.HasRequiredRole() {
|
||||||
|
set, err := c.policy.QueryPolicy(r.Request.Context(),
|
||||||
|
policy.NewQueryPolicyRequest().
|
||||||
|
SetNamespaceId(tk.NamespaceId).
|
||||||
|
SetUserId(tk.UserId).
|
||||||
|
SetExpired(false).
|
||||||
|
SetEnabled(true).
|
||||||
|
SetWithRole(true),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return exception.NewInternalServerError("%s", err.Error())
|
||||||
|
}
|
||||||
|
hasPerm := false
|
||||||
|
for i := range set.Items {
|
||||||
|
p := set.Items[i]
|
||||||
|
if route.IsRequireRole(p.Role.Name) {
|
||||||
|
hasPerm = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasPerm {
|
||||||
|
return exception.NewPermissionDeny("无权限访问")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// API权限校验
|
||||||
|
if route.RequiredPerm {
|
||||||
|
validateReq := policy.NewValidateEndpointPermissionRequest()
|
||||||
|
validateReq.UserId = tk.UserId
|
||||||
|
validateReq.NamespaceId = tk.NamespaceId
|
||||||
|
validateReq.Service = application.Get().GetAppName()
|
||||||
|
validateReq.Method = route.Method
|
||||||
|
validateReq.Path = route.Path
|
||||||
|
resp, err := c.policy.ValidateEndpointPermission(r.Request.Context(), validateReq)
|
||||||
|
if err != nil {
|
||||||
|
return exception.NewInternalServerError("%s", err.Error())
|
||||||
|
}
|
||||||
|
if !resp.HasPermission {
|
||||||
|
return exception.NewPermissionDeny("无权限访问")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user