mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
feat: 系统配置新增权限控制
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
package form
|
||||
|
||||
type LoginForm struct {
|
||||
Username string `json:"username" binding:"required"`
|
||||
Password string `binding:"required"`
|
||||
Captcha string `json:"captcha"`
|
||||
Cid string `json:"cid"`
|
||||
LdapLogin bool `json:"ldapLogin"`
|
||||
Username string `json:"username" binding:"required"`
|
||||
Password string `binding:"required"`
|
||||
Captcha string `json:"captcha"`
|
||||
Cid string `json:"cid"`
|
||||
}
|
||||
|
||||
type OtpVerfiy struct {
|
||||
|
||||
@@ -3,7 +3,6 @@ package api
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"mayfly-go/internal/auth/api/form"
|
||||
msgapp "mayfly-go/internal/msg/application"
|
||||
sysapp "mayfly-go/internal/sys/application"
|
||||
@@ -18,6 +17,8 @@ import (
|
||||
"mayfly-go/pkg/utils/cryptox"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type LdapLogin struct {
|
||||
@@ -28,16 +29,18 @@ type LdapLogin struct {
|
||||
|
||||
// @router /auth/ldap/enabled [get]
|
||||
func (a *LdapLogin) GetLdapEnabled(rc *req.Ctx) {
|
||||
rc.ResData = config.Conf.Ldap.Enabled
|
||||
if config.Conf.Ldap != nil {
|
||||
rc.ResData = config.Conf.Ldap.Enabled
|
||||
return
|
||||
}
|
||||
|
||||
rc.ResData = false
|
||||
}
|
||||
|
||||
// @router /auth/ldap/login [post]
|
||||
func (a *LdapLogin) Login(rc *req.Ctx) {
|
||||
loginForm := ginx.BindJsonAndValid(rc.GinCtx, new(form.LoginForm))
|
||||
|
||||
// 确认是 LDAP 登录
|
||||
biz.IsTrue(loginForm.LdapLogin, "LDAP 登录参数错误")
|
||||
|
||||
accountLoginSecurity := a.ConfigApp.GetConfig(sysentity.ConfigKeyAccountLoginSecurity).ToAccountLoginSecurity()
|
||||
// 判断是否有开启登录验证码校验
|
||||
if accountLoginSecurity.UseCaptcha {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"mayfly-go/pkg/ginx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/req"
|
||||
"mayfly-go/pkg/utils/jsonx"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -71,14 +72,14 @@ func (m *Mongo) DeleteMongo(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) Databases(rc *req.Ctx) {
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
|
||||
cli := m.MongoApp.GetMongoInst(m.GetMongoId(rc.GinCtx)).Cli
|
||||
res, err := cli.ListDatabases(context.TODO(), bson.D{})
|
||||
biz.ErrIsNilAppendErr(err, "获取mongo所有库信息失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Mongo) Collections(rc *req.Ctx) {
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
|
||||
cli := m.MongoApp.GetMongoInst(m.GetMongoId(rc.GinCtx)).Cli
|
||||
db := rc.GinCtx.Query("database")
|
||||
biz.NotEmpty(db, "database不能为空")
|
||||
ctx := context.TODO()
|
||||
@@ -90,8 +91,13 @@ func (m *Mongo) Collections(rc *req.Ctx) {
|
||||
func (m *Mongo) RunCommand(rc *req.Ctx) {
|
||||
commandForm := new(form.MongoRunCommand)
|
||||
ginx.BindJsonAndValid(rc.GinCtx, commandForm)
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
|
||||
rc.ReqParam = commandForm
|
||||
|
||||
inst := m.MongoApp.GetMongoInst(m.GetMongoId(rc.GinCtx))
|
||||
|
||||
rc.ReqParam = jsonx.ToStr(map[string]any{
|
||||
"info": inst.Info.GetLogDesc(),
|
||||
"req": commandForm,
|
||||
})
|
||||
|
||||
// 顺序执行
|
||||
commands := bson.D{}
|
||||
@@ -106,7 +112,7 @@ func (m *Mongo) RunCommand(rc *req.Ctx) {
|
||||
|
||||
ctx := context.TODO()
|
||||
var bm bson.M
|
||||
err := cli.Database(commandForm.Database).RunCommand(
|
||||
err := inst.Cli.Database(commandForm.Database).RunCommand(
|
||||
ctx,
|
||||
commands,
|
||||
).Decode(&bm)
|
||||
@@ -117,7 +123,7 @@ func (m *Mongo) RunCommand(rc *req.Ctx) {
|
||||
|
||||
func (m *Mongo) FindCommand(rc *req.Ctx) {
|
||||
g := rc.GinCtx
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
|
||||
cli := m.MongoApp.GetMongoInst(m.GetMongoId(g)).Cli
|
||||
commandForm := new(form.MongoFindCommand)
|
||||
ginx.BindJsonAndValid(g, commandForm)
|
||||
|
||||
@@ -150,10 +156,15 @@ func (m *Mongo) FindCommand(rc *req.Ctx) {
|
||||
|
||||
func (m *Mongo) UpdateByIdCommand(rc *req.Ctx) {
|
||||
g := rc.GinCtx
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
|
||||
commandForm := new(form.MongoUpdateByIdCommand)
|
||||
ginx.BindJsonAndValid(g, commandForm)
|
||||
|
||||
inst := m.MongoApp.GetMongoInst(m.GetMongoId(g))
|
||||
rc.ReqParam = jsonx.ToStr(map[string]any{
|
||||
"info": inst.Info.GetLogDesc(),
|
||||
"req": commandForm,
|
||||
})
|
||||
|
||||
// 解析docId文档id,如果为string类型则使用ObjectId解析,解析失败则为普通字符串
|
||||
docId := commandForm.DocId
|
||||
docIdVal, ok := docId.(string)
|
||||
@@ -164,19 +175,23 @@ func (m *Mongo) UpdateByIdCommand(rc *req.Ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).UpdateByID(context.TODO(), docId, commandForm.Update)
|
||||
res, err := inst.Cli.Database(commandForm.Database).Collection(commandForm.Collection).UpdateByID(context.TODO(), docId, commandForm.Update)
|
||||
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
|
||||
|
||||
rc.ReqParam = commandForm
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Mongo) DeleteByIdCommand(rc *req.Ctx) {
|
||||
g := rc.GinCtx
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
|
||||
commandForm := new(form.MongoUpdateByIdCommand)
|
||||
ginx.BindJsonAndValid(g, commandForm)
|
||||
|
||||
inst := m.MongoApp.GetMongoInst(m.GetMongoId(g))
|
||||
rc.ReqParam = jsonx.ToStr(map[string]any{
|
||||
"info": inst.Info.GetLogDesc(),
|
||||
"req": commandForm,
|
||||
})
|
||||
|
||||
// 解析docId文档id,如果为string类型则使用ObjectId解析,解析失败则为普通字符串
|
||||
docId := commandForm.DocId
|
||||
docIdVal, ok := docId.(string)
|
||||
@@ -187,23 +202,24 @@ func (m *Mongo) DeleteByIdCommand(rc *req.Ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).DeleteOne(context.TODO(), bson.D{{"_id", docId}})
|
||||
res, err := inst.Cli.Database(commandForm.Database).Collection(commandForm.Collection).DeleteOne(context.TODO(), bson.D{{Key: "_id", Value: docId}})
|
||||
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
|
||||
|
||||
rc.ReqParam = commandForm
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
func (m *Mongo) InsertOneCommand(rc *req.Ctx) {
|
||||
g := rc.GinCtx
|
||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(g))
|
||||
commandForm := new(form.MongoInsertCommand)
|
||||
ginx.BindJsonAndValid(g, commandForm)
|
||||
|
||||
res, err := cli.Database(commandForm.Database).Collection(commandForm.Collection).InsertOne(context.TODO(), commandForm.Doc)
|
||||
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
|
||||
inst := m.MongoApp.GetMongoInst(m.GetMongoId(g))
|
||||
rc.ReqParam = jsonx.ToStr(map[string]any{
|
||||
"info": inst.Info.GetLogDesc(),
|
||||
"req": commandForm,
|
||||
})
|
||||
|
||||
rc.ReqParam = commandForm
|
||||
res, err := inst.Cli.Database(commandForm.Database).Collection(commandForm.Collection).InsertOne(context.TODO(), commandForm.Doc)
|
||||
biz.ErrIsNilAppendErr(err, "命令执行失败: %s")
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ type Mongo interface {
|
||||
// 删除数据库信息
|
||||
Delete(id uint64)
|
||||
|
||||
// 获取mongo连接client
|
||||
// 获取mongo连接实例
|
||||
// @param id mongo id
|
||||
GetMongoCli(id uint64) *mongo.Client
|
||||
GetMongoInst(id uint64) *MongoInstance
|
||||
}
|
||||
|
||||
func newMongoAppImpl(mongoRepo repository.Mongo) Mongo {
|
||||
@@ -88,14 +88,14 @@ func (d *mongoAppImpl) Save(m *entity.Mongo) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *mongoAppImpl) GetMongoCli(id uint64) *mongo.Client {
|
||||
func (d *mongoAppImpl) GetMongoInst(id uint64) *MongoInstance {
|
||||
mongoInstance, err := GetMongoInstance(id, func(u uint64) *entity.Mongo {
|
||||
mongo := d.GetById(u)
|
||||
biz.NotNil(mongo, "mongo信息不存在")
|
||||
return mongo
|
||||
})
|
||||
biz.ErrIsNilAppendErr(err, "连接mongo失败: %s")
|
||||
return mongoInstance.Cli
|
||||
return mongoInstance
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
@@ -173,7 +173,7 @@ func connect(me *entity.Mongo) (*MongoInstance, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
mongoInstance := &MongoInstance{Id: me.Id, Info: toMongiInfo(me)}
|
||||
mongoInstance := &MongoInstance{Id: me.Id, Info: toMongoInfo(me)}
|
||||
|
||||
mongoOptions := options.Client().ApplyURI(me.Uri).
|
||||
SetMaxPoolSize(1)
|
||||
@@ -200,7 +200,7 @@ func connect(me *entity.Mongo) (*MongoInstance, error) {
|
||||
return mongoInstance, err
|
||||
}
|
||||
|
||||
func toMongiInfo(me *entity.Mongo) *MongoInfo {
|
||||
func toMongoInfo(me *entity.Mongo) *MongoInfo {
|
||||
mi := new(MongoInfo)
|
||||
structx.Copy(mi, me)
|
||||
return mi
|
||||
|
||||
@@ -16,28 +16,22 @@ type Config struct {
|
||||
func (c *Config) Configs(rc *req.Ctx) {
|
||||
g := rc.GinCtx
|
||||
condition := &entity.Config{Key: g.Query("key")}
|
||||
condition.Permission = rc.LoginAccount.Username
|
||||
rc.ResData = c.ConfigApp.GetPageList(condition, ginx.GetPageParam(g), new([]entity.Config))
|
||||
}
|
||||
|
||||
func (c *Config) GetConfigValueByKey(rc *req.Ctx) {
|
||||
key := rc.GinCtx.Query("key")
|
||||
biz.NotEmpty(key, "key不能为空")
|
||||
rc.ResData = c.ConfigApp.GetConfig(key).Value
|
||||
}
|
||||
|
||||
func (c *Config) GetConfigValueByKeyWithNoToken(keys []string) func(rc *req.Ctx) {
|
||||
keyMap := make(map[string]struct{})
|
||||
for _, key := range keys {
|
||||
keyMap[key] = struct{}{}
|
||||
}
|
||||
return func(rc *req.Ctx) {
|
||||
key := rc.GinCtx.Query("key")
|
||||
biz.NotEmpty(key, "key不能为空")
|
||||
if _, ok := keyMap[key]; !ok {
|
||||
biz.ErrIsNil(nil, "无权限获取该配置信息")
|
||||
}
|
||||
rc.ResData = c.ConfigApp.GetConfig(key).Value
|
||||
config := c.ConfigApp.GetConfig(key)
|
||||
// 判断是否为公开配置
|
||||
if config.Permission != "all" {
|
||||
rc.ResData = ""
|
||||
return
|
||||
}
|
||||
|
||||
rc.ResData = config.Value
|
||||
}
|
||||
|
||||
func (c *Config) SaveConfig(rc *req.Ctx) {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package form
|
||||
|
||||
type ConfigForm struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Params string `json:"params"`
|
||||
Value string `json:"value"`
|
||||
Remark string `json:"remark"`
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
Params string `json:"params"`
|
||||
Value string `json:"value"`
|
||||
Remark string `json:"remark"`
|
||||
Permission string `json:"permission"`
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"encoding/json"
|
||||
"mayfly-go/internal/sys/domain/entity"
|
||||
"mayfly-go/internal/sys/domain/repository"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/cache"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/jsonx"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const SysConfigKeyPrefix = "mayfly:sys:config:"
|
||||
@@ -39,6 +41,11 @@ func (a *configAppImpl) Save(config *entity.Config) {
|
||||
if config.Id == 0 {
|
||||
a.configRepo.Insert(config)
|
||||
} else {
|
||||
oldConfig := a.GetConfig(config.Key)
|
||||
if oldConfig.Permission != "all" {
|
||||
biz.IsTrue(strings.Contains(oldConfig.Permission, config.Modifier), "您无权修改该配置")
|
||||
}
|
||||
|
||||
a.configRepo.Update(config)
|
||||
}
|
||||
cache.Del(SysConfigKeyPrefix + config.Key)
|
||||
@@ -53,7 +60,7 @@ func (a *configAppImpl) GetConfig(key string) *entity.Config {
|
||||
return config
|
||||
}
|
||||
|
||||
if err := a.configRepo.GetConfig(config, "Id", "Key", "Value"); err != nil {
|
||||
if err := a.configRepo.GetConfig(config, "Id", "Key", "Value", "Permission"); err != nil {
|
||||
global.Log.Warnf("不存在key = [%s] 的系统配置", key)
|
||||
} else {
|
||||
cache.SetStr(SysConfigKeyPrefix+key, jsonx.ToStr(config), -1)
|
||||
|
||||
@@ -16,11 +16,12 @@ const (
|
||||
|
||||
type Config struct {
|
||||
model.Model
|
||||
Name string `json:"name"` // 配置名
|
||||
Key string `json:"key"` // 配置key
|
||||
Params string `json:"params" gorm:"column:params;type:varchar(1500)"`
|
||||
Value string `json:"value" gorm:"column:value;type:varchar(1500)"`
|
||||
Remark string `json:"remark"`
|
||||
Name string `json:"name"` // 配置名
|
||||
Key string `json:"key"` // 配置key
|
||||
Params string `json:"params" gorm:"column:params;type:varchar(1500)"`
|
||||
Value string `json:"value" gorm:"column:value;type:varchar(1500)"`
|
||||
Remark string `json:"remark"`
|
||||
Permission string `json:"permission"` // 可操作该配置的权限
|
||||
}
|
||||
|
||||
func (a *Config) TableName() string {
|
||||
|
||||
@@ -15,7 +15,10 @@ func newConfigRepo() repository.Config {
|
||||
}
|
||||
|
||||
func (m *configRepoImpl) GetPageList(condition *entity.Config, pageParam *model.PageParam, toEntity any, orderBy ...string) *model.PageResult[any] {
|
||||
qd := gormx.NewQuery(condition).WithCondModel(condition).WithOrderBy(orderBy...)
|
||||
qd := gormx.NewQuery(condition).
|
||||
Eq("key", condition.Key).
|
||||
And("permission = 'all' OR permission LIKE ?", "%"+condition.Permission+",%").
|
||||
WithOrderBy(orderBy...)
|
||||
return gormx.PageQuery(qd, pageParam, toEntity)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package router
|
||||
import (
|
||||
"mayfly-go/internal/sys/api"
|
||||
"mayfly-go/internal/sys/application"
|
||||
"mayfly-go/internal/sys/domain/entity"
|
||||
"mayfly-go/pkg/req"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -19,12 +18,7 @@ func InitSysConfigRouter(router *gin.RouterGroup) {
|
||||
req.NewGet("", r.Configs).RequiredPermission(baseP),
|
||||
|
||||
// 获取指定配置key对应的值
|
||||
req.NewGet("/value", r.GetConfigValueByKeyWithNoToken([]string{
|
||||
entity.ConfigKeyAccountLoginSecurity,
|
||||
entity.ConfigKeyDbQueryMaxCount,
|
||||
entity.ConfigKeyDbSaveQuerySQL,
|
||||
entity.ConfigUseWartermark,
|
||||
})).DontNeedToken(),
|
||||
req.NewGet("/value", r.GetConfigValueByKey).DontNeedToken(),
|
||||
|
||||
req.NewGet("/oauth2-login", r.Oauth2Config).DontNeedToken(),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user