mirror of
https://github.com/veops/oneterm.git
synced 2025-09-26 19:31:14 +08:00
feat(api): agent CRUD
This commit is contained in:
@@ -109,3 +109,18 @@ type UserInfoRespResult struct {
|
||||
UID int `json:"uid"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
type AuthWithKeyResp struct {
|
||||
User AuthWithKeyResult `json:"user"`
|
||||
}
|
||||
|
||||
type AuthWithKeyResult struct {
|
||||
Avatar string `json:"avatar"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Rid int `json:"rid"`
|
||||
Role Role `json:"role"`
|
||||
UID int `json:"uid"`
|
||||
Username string `json:"username"`
|
||||
ParentRoles []string `json:"parentRoles"`
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/veops/oneterm/conf"
|
||||
@@ -141,24 +142,40 @@ func NewSignature(secret, salt, sep, derivation string, digest func() hash.Hash,
|
||||
}
|
||||
|
||||
func AuthWithKey(path string, originData map[string]any) (sess *Session, err error) {
|
||||
originData["path"] = path
|
||||
|
||||
data := &UserInfoRespResult{}
|
||||
body := map[string]any{
|
||||
"path": path,
|
||||
"key": originData["_key"],
|
||||
"secret": originData["_secret"],
|
||||
"need_parentRoles": true,
|
||||
"app_id": "oneterm",
|
||||
}
|
||||
payload := make(map[string]any)
|
||||
for k, v := range originData {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() == reflect.Map || rv.Kind() == reflect.Slice || rv.Kind() == reflect.Array {
|
||||
continue
|
||||
}
|
||||
payload[k] = v
|
||||
}
|
||||
body["payload"] = payload
|
||||
url := fmt.Sprintf("%s%s", conf.Cfg.Auth.Acl.Url, "/acl/auth_with_key")
|
||||
data := &AuthWithKeyResp{}
|
||||
resp, err := remote.RC.R().
|
||||
SetBody(originData).
|
||||
SetBody(body).
|
||||
SetResult(data).
|
||||
Post(fmt.Sprintf("%s%s", conf.Cfg.Auth.Acl.Url, "/acl/apps/token"))
|
||||
Post(url)
|
||||
if err = remote.HandleErr(err, resp, nil); err == nil {
|
||||
sess = &Session{
|
||||
Uid: data.UID,
|
||||
Uid: data.User.UID,
|
||||
Acl: Acl{
|
||||
Uid: data.UID,
|
||||
UserName: data.Username,
|
||||
Rid: data.Rid,
|
||||
NickName: data.Name,
|
||||
ParentRoles: data.Role.Permissions,
|
||||
Uid: data.User.UID,
|
||||
UserName: data.User.Username,
|
||||
Rid: data.User.Rid,
|
||||
NickName: data.User.Name,
|
||||
ParentRoles: data.User.ParentRoles,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@@ -19,6 +19,22 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
assetPreHooks = []preHook[*model.Asset]{
|
||||
func(ctx *gin.Context, data *model.Asset) {
|
||||
if data.AccessAuth == nil {
|
||||
data.AccessAuth = &model.AccessAuth{
|
||||
Start: nil,
|
||||
End: nil,
|
||||
CmdIds: make(model.Slice[int], 0),
|
||||
Ranges: make(model.Slice[model.Range], 0),
|
||||
Allow: true,
|
||||
}
|
||||
}
|
||||
if data.Authorization == nil {
|
||||
data.Authorization = make(model.Map[int, model.Slice[int]])
|
||||
}
|
||||
},
|
||||
}
|
||||
assetPostHooks = []postHook[*model.Asset]{assetPostHookCount, assetPostHookAuth}
|
||||
)
|
||||
|
||||
@@ -30,7 +46,8 @@ var (
|
||||
// @Router /asset [post]
|
||||
func (c *Controller) CreateAsset(ctx *gin.Context) {
|
||||
asset := &model.Asset{}
|
||||
doCreate(ctx, true, asset, conf.RESOURCE_ASSET)
|
||||
doCreate(ctx, true, asset, conf.RESOURCE_ASSET, assetPreHooks...)
|
||||
|
||||
schedule.CheckUpdate(asset.Id)
|
||||
}
|
||||
|
||||
|
@@ -261,16 +261,23 @@ func doUpdate[T model.Model](ctx *gin.Context, needAcl bool, md T, preHooks ...p
|
||||
|
||||
if err = mysql.DB.Transaction(func(tx *gorm.DB) (err error) {
|
||||
omits := []string{"resource_id", "created_at", "deleted_at"}
|
||||
selects := []string{"*"}
|
||||
switch t := any(md).(type) {
|
||||
case *model.Asset:
|
||||
if err = HandleAuthorization(currentUser, tx, model.ACTION_UPDATE, any(old).(*model.Asset), t); err != nil {
|
||||
handleRemoteErr(ctx, err)
|
||||
return
|
||||
}
|
||||
omits = append(omits, "ci_id")
|
||||
if cast.ToBool(ctx.Value("isAuthWithKey")) {
|
||||
selects = []string{"ip", "protocols", "authorization"}
|
||||
}
|
||||
case *model.Account:
|
||||
if cast.ToBool(ctx.Value("isAuthWithKey")) {
|
||||
selects = []string{"password", "phrase", "pk", "account_type"}
|
||||
}
|
||||
}
|
||||
|
||||
if err = mysql.DB.Omit(omits...).Save(md).Error; err != nil {
|
||||
if err = mysql.DB.Select(selects).Omit(omits...).Save(md).Error; err != nil {
|
||||
return
|
||||
}
|
||||
err = mysql.DB.Create(&model.History{
|
||||
@@ -306,7 +313,6 @@ func doGet[T any](ctx *gin.Context, needAcl bool, dbFind *gorm.DB, resourceType
|
||||
currentUser, _ := acl.GetSessionFromCtx(ctx)
|
||||
|
||||
if needAcl && !acl.IsAdmin(currentUser) {
|
||||
//rs := make([]*acl.Resource, 0)
|
||||
var rs []*acl.Resource
|
||||
rs, err = acl.GetRoleResources(ctx, currentUser.Acl.Rid, resourceType)
|
||||
if err != nil {
|
||||
@@ -330,8 +336,8 @@ func doGet[T any](ctx *gin.Context, needAcl bool, dbFind *gorm.DB, resourceType
|
||||
if _, ok := ctx.GetQuery("page_index"); ok {
|
||||
dbFind = dbFind.Offset((pi - 1) * ps)
|
||||
}
|
||||
if _, ok := ctx.GetQuery("page_size"); ok {
|
||||
dbFind = dbFind.Limit(ps)
|
||||
if _, ok := ctx.GetQuery("page_size"); ok && ps != -1 {
|
||||
dbFind = dbFind.Limit(lo.Ternary(ps == 0, 20, ps))
|
||||
}
|
||||
return dbFind.
|
||||
Order("id DESC").
|
||||
|
@@ -25,6 +25,7 @@ const (
|
||||
ErrAccessTime = 4011
|
||||
ErrIdleTimeout = 4012
|
||||
ErrWrongPvk = 4013
|
||||
ErrUnauthorized = 4401
|
||||
ErrInternal = 5000
|
||||
ErrRemoteServer = 5001
|
||||
ErrConnectServer = 5002
|
||||
@@ -48,6 +49,7 @@ var (
|
||||
ErrLogin: myi18n.MsgLoginError,
|
||||
ErrAccessTime: myi18n.MsgAccessTime,
|
||||
ErrIdleTimeout: myi18n.MsgIdleTimeout,
|
||||
ErrUnauthorized: myi18n.MsgUnauthorized,
|
||||
ErrInternal: myi18n.MsgInternalError,
|
||||
ErrRemoteServer: myi18n.MsgRemoteServer,
|
||||
ErrConnectServer: myi18n.MsgConnectServer,
|
||||
|
@@ -17,6 +17,10 @@ import (
|
||||
"github.com/veops/oneterm/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
errUnauthorized = &controller.ApiError{Code: controller.ErrUnauthorized}
|
||||
)
|
||||
|
||||
func ginLogger() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
start := time.Now()
|
||||
@@ -44,18 +48,25 @@ func auth() gin.HandlerFunc {
|
||||
|
||||
m := make(map[string]any)
|
||||
ctx.ShouldBindBodyWithJSON(&m)
|
||||
if _, ok := m["key"]; ok {
|
||||
if ctx.Request.Method == "GET" {
|
||||
if _, ok := ctx.GetQuery("_key"); ok {
|
||||
m["_key"] = ctx.Query("_key")
|
||||
m["_secret"] = ctx.Query("_secret")
|
||||
}
|
||||
}
|
||||
if _, ok := m["_key"]; ok {
|
||||
sess, err = acl.AuthWithKey(ctx.Request.URL.Path, m)
|
||||
if err != nil {
|
||||
logger.L().Error("cannot authwithkey", zap.Error(err))
|
||||
ctx.AbortWithStatus(http.StatusUnauthorized)
|
||||
ctx.AbortWithError(http.StatusUnauthorized, errUnauthorized)
|
||||
return
|
||||
}
|
||||
ctx.Set("isAuthWithKey", true)
|
||||
} else {
|
||||
cookie, err = ctx.Cookie("session")
|
||||
if err != nil || cookie == "" {
|
||||
logger.L().Error("cannot get cookie.session", zap.Error(err))
|
||||
ctx.AbortWithStatus(http.StatusUnauthorized)
|
||||
ctx.AbortWithError(http.StatusUnauthorized, errUnauthorized)
|
||||
return
|
||||
}
|
||||
sess, err = acl.ParseCookie(cookie)
|
||||
|
5
backend/cache/redis.go
vendored
5
backend/cache/redis.go
vendored
@@ -20,13 +20,14 @@ var (
|
||||
|
||||
func init() {
|
||||
ctx := context.Background()
|
||||
addr := fmt.Sprintf("%s:%d", conf.Cfg.Redis.Host, conf.Cfg.Redis.Port)
|
||||
RC = redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%s:%d", conf.Cfg.Redis.Host, conf.Cfg.Redis.Port),
|
||||
Addr: addr,
|
||||
Password: conf.Cfg.Redis.Password,
|
||||
})
|
||||
|
||||
if _, err := RC.Ping(ctx).Result(); err != nil {
|
||||
logger.L().Fatal("ping redis failed", zap.Error(err))
|
||||
logger.L().Fatal("ping redis failed", zap.String("addr", addr), zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -103,6 +103,11 @@ var (
|
||||
One: "Bad Request: idle timeout more than {{.second}} seconds",
|
||||
Other: "Bad Request: idle timeout more than {{.second}} seconds",
|
||||
}
|
||||
MsgUnauthorized = &i18n.Message{
|
||||
ID: "MsgUnauthorized",
|
||||
One: "Unauthorized",
|
||||
Other: "Unauthorized",
|
||||
}
|
||||
//
|
||||
MsgInternalError = &i18n.Message{
|
||||
ID: "MsgInternalError",
|
||||
|
@@ -12,7 +12,6 @@ const (
|
||||
|
||||
type Asset struct {
|
||||
Id int `json:"id" gorm:"column:id;primarykey"`
|
||||
Ciid int `json:"ci_id" gorm:"column:ci_id"`
|
||||
Name string `json:"name" gorm:"column:name"`
|
||||
Comment string `json:"comment" gorm:"column:comment"`
|
||||
ParentId int `json:"parent_id" gorm:"column:parent_id"`
|
||||
|
@@ -17,7 +17,6 @@ type Node struct {
|
||||
ParentId int `json:"parent_id" gorm:"column:parent_id"`
|
||||
Authorization Map[int, Slice[int]] `json:"authorization" gorm:"column:authorization"`
|
||||
*AccessAuth `json:"access_auth" gorm:"column:access_auth"`
|
||||
*Sync `json:"sync" gorm:"column:sync"`
|
||||
Protocols Slice[string] `json:"protocols" gorm:"column:protocols"`
|
||||
GatewayId int `json:"gateway_id" gorm:"column:gateway_id"`
|
||||
|
||||
@@ -32,14 +31,6 @@ type Node struct {
|
||||
HasChild bool `json:"has_child" gorm:"-"`
|
||||
}
|
||||
|
||||
type Sync struct {
|
||||
TypeId int `json:"type_id,omitempty" gorm:"column:type_id"`
|
||||
Mapping Map[string, string] `json:"mapping" gorm:"column:mapping"`
|
||||
Filters string `json:"filters" gorm:"column:filters"`
|
||||
Enable bool `json:"enable" gorm:"column:enable"`
|
||||
Frequency float64 `json:"frequency" gorm:"column:frequency"`
|
||||
}
|
||||
|
||||
func (m *Node) TableName() string {
|
||||
return TABLE_NAME_NODE
|
||||
}
|
||||
|
@@ -100,11 +100,6 @@ CREATE TABLE
|
||||
`cmd_ids` JSON NOT NULL,
|
||||
`ranges` JSON NOT NULL,
|
||||
`allow` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`type_id` INT NOT NULL DEFAULT 0,
|
||||
`mapping` JSON NOT NULL,
|
||||
`filters` TEXT NOT NULL,
|
||||
`enable` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`frequency` DOUBLE NOT NULL DEFAULT 0,
|
||||
`creator_id` INT NOT NULL DEFAULT 0,
|
||||
`created_at` TIMESTAMP NOT NULL,
|
||||
`updater_id` INT NOT NULL DEFAULT 0,
|
||||
|
@@ -7,21 +7,30 @@ http:
|
||||
ssh:
|
||||
host: 0.0.0.0
|
||||
port: 2222
|
||||
privateKey: --BEGIN PRIVATE KEY-----END PRIVATE KEY-----
|
||||
privateKey: |
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACBg490b4zqumtizCyM4RWtzJnPEsPIInBFugk8+UCb8XgAAAKCc1yKrnNci
|
||||
qwAAAAtzc2gtZWQyNTUxOQAAACBg490b4zqumtizCyM4RWtzJnPEsPIInBFugk8+UCb8Xg
|
||||
AAAECvd1Yj+bQxyxJtU3PirLK68CD3MWqBv0/shlFKS6wmbWDj3RvjOq6a2LMLIzhFa3Mm
|
||||
c8Sw8gicEW6CTz5QJvxeAAAAGnJvb3RAbG9jYWxob3N0LmxvY2FsZG9tYWluAQID
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
||||
|
||||
guacd:
|
||||
host: oneterm-guacd
|
||||
port: 4822
|
||||
|
||||
mysql:
|
||||
host: oneterm-mysql
|
||||
host: mysql
|
||||
port: 3306
|
||||
user: root
|
||||
password: root
|
||||
password: "123456"
|
||||
|
||||
redis:
|
||||
addr: oneterm-redis:6379
|
||||
password: root
|
||||
host: redis
|
||||
port: 6379
|
||||
password: ""
|
||||
|
||||
log:
|
||||
level: debug
|
||||
@@ -33,7 +42,7 @@ auth:
|
||||
acl:
|
||||
appId: acl app id
|
||||
secretKey: acl app secret key
|
||||
url: http://host/api/v1
|
||||
url: http://acl-api/api/v1
|
||||
resourceNames:
|
||||
- key: account
|
||||
value: account
|
||||
@@ -46,4 +55,4 @@ auth:
|
||||
- key: authorization
|
||||
value: authorization
|
||||
|
||||
secretKey: acl secret key
|
||||
secretKey: xW2FAUfgffjmerTEBXADmURDOQ43ojLN
|
||||
|
@@ -2,7 +2,7 @@ version: "3.0"
|
||||
|
||||
services:
|
||||
oneterm-api:
|
||||
# image: registry.cn-hangzhou.aliyuncs.com/veops/oneterm-api:24.3
|
||||
image: oneterm:dev
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ../backend/dockerfile
|
||||
@@ -51,13 +51,10 @@ services:
|
||||
new:
|
||||
aliases:
|
||||
- mysql
|
||||
ports:
|
||||
- '23306:3306'
|
||||
|
||||
redis:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/veops/redis:latest
|
||||
container_name: oneterm-redis
|
||||
#command: redis-server --requirepass tyrj5QVP9rHs
|
||||
restart: always
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
@@ -73,7 +70,7 @@ services:
|
||||
- oneterm-api
|
||||
environment:
|
||||
TZ: Asia/Shanghai
|
||||
ONETERM_API_HOST: oneterm-api:8080
|
||||
ONETERM_API_HOST: oneterm-api:8888
|
||||
ACL_API_HOST: acl-api:5000
|
||||
NGINX_PORT: 80
|
||||
volumes:
|
||||
@@ -88,13 +85,13 @@ services:
|
||||
networks:
|
||||
- new
|
||||
ports:
|
||||
- "8000:80"
|
||||
- "8666:80"
|
||||
|
||||
acl-api:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/veops/acl-api:1.1
|
||||
container_name: oneterm-acl-api
|
||||
environment:
|
||||
#TZ: Asia/Shanghai
|
||||
TZ: Asia/Shanghai
|
||||
WAIT_HOSTS: mysql:3306, redis:6379
|
||||
volumes:
|
||||
- ./.env:/data/apps/acl/.env
|
||||
|
Reference in New Issue
Block a user