diff --git a/backend/app/api/v1/database_mysql.go b/backend/app/api/v1/database_mysql.go index a3aec9b16..b6c5f9282 100644 --- a/backend/app/api/v1/database_mysql.go +++ b/backend/app/api/v1/database_mysql.go @@ -41,6 +41,37 @@ func (b *BaseApi) CreateMysql(c *gin.Context) { helper.SuccessWithData(c, nil) } +// @Tags Database Mysql +// @Summary Bind user of mysql database +// @Description 绑定 mysql 数据库用户 +// @Accept json +// @Param request body dto.BindUser true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /databases/bind [post] +// @x-panel-log {"bodyKeys":["database", "username"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"绑定 mysql 数据库名 [database] [username]","formatEN":"bind mysql database [database] [username]"} +func (b *BaseApi) BindUser(c *gin.Context) { + var req dto.BindUser + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + + if len(req.Password) != 0 { + password, err := base64.StdEncoding.DecodeString(req.Password) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + req.Password = string(password) + } + + if err := mysqlService.BindUser(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + // @Tags Database Mysql // @Summary Update mysql database description // @Description 更新 mysql 数据库库描述信息 diff --git a/backend/app/dto/database.go b/backend/app/dto/database.go index cdf1966df..65aaa0ab4 100644 --- a/backend/app/dto/database.go +++ b/backend/app/dto/database.go @@ -43,6 +43,14 @@ type MysqlDBCreate struct { Description string `json:"description"` } +type BindUser struct { + Database string `json:"database" validate:"required"` + DB string `json:"db" validate:"required"` + Username string `json:"username" validate:"required"` + Password string `json:"password" validate:"required"` + Permission string `json:"permission" validate:"required"` +} + type MysqlLoadDB struct { From string `json:"from" validate:"required,oneof=local remote"` Type string `json:"type" validate:"required,oneof=mysql mariadb"` diff --git a/backend/app/service/database_mysql.go b/backend/app/service/database_mysql.go index cf61f1241..fe293bc9e 100644 --- a/backend/app/service/database_mysql.go +++ b/backend/app/service/database_mysql.go @@ -35,6 +35,7 @@ type IMysqlService interface { SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) ListDBOption() ([]dto.MysqlOption, error) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) + BindUser(req dto.BindUser) error LoadFromRemote(req dto.MysqlLoadDB) error ChangeAccess(info dto.ChangeDBInfo) error ChangePassword(info dto.ChangeDBInfo) error @@ -144,6 +145,42 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode return &createItem, nil } +func (u *MysqlService) BindUser(req dto.BindUser) error { + dbItem, err := mysqlRepo.Get(mysqlRepo.WithByMysqlName(req.Database), commonRepo.WithByName(req.DB)) + if err != nil { + return err + } + cli, version, err := LoadMysqlClientByFrom(req.Database) + if err != nil { + return err + } + defer cli.Close() + + if err := cli.CreateUser(client.CreateInfo{ + Name: dbItem.Name, + Format: dbItem.Format, + Username: req.Username, + Password: req.Password, + Permission: req.Permission, + Version: version, + Timeout: 300, + }, false); err != nil { + return err + } + pass, err := encrypt.StringEncrypt(req.Password) + if err != nil { + return fmt.Errorf("decrypt database db password failed, err: %v", err) + } + if err := mysqlRepo.Update(dbItem.ID, map[string]interface{}{ + "username": req.Username, + "password": pass, + "permission": req.Permission, + }); err != nil { + return err + } + return nil +} + func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error { client, version, err := LoadMysqlClientByFrom(req.Database) if err != nil { diff --git a/backend/router/ro_database.go b/backend/router/ro_database.go index d62e4f283..88fa214f4 100644 --- a/backend/router/ro_database.go +++ b/backend/router/ro_database.go @@ -17,6 +17,7 @@ func (s *DatabaseRouter) InitRouter(Router *gin.RouterGroup) { baseApi := v1.ApiGroupApp.BaseApi { cmdRouter.POST("", baseApi.CreateMysql) + cmdRouter.POST("/bind", baseApi.BindUser) cmdRouter.POST("load", baseApi.LoadDBFromRemote) cmdRouter.POST("/change/access", baseApi.ChangeMysqlAccess) cmdRouter.POST("/change/password", baseApi.ChangeMysqlPassword) diff --git a/backend/utils/mysql/client.go b/backend/utils/mysql/client.go index 7af24ff06..14225adf9 100644 --- a/backend/utils/mysql/client.go +++ b/backend/utils/mysql/client.go @@ -14,6 +14,7 @@ import ( type MysqlClient interface { Create(info client.CreateInfo) error + CreateUser(info client.CreateInfo, withDeleteDB bool) error Delete(info client.DeleteInfo) error ChangePassword(info client.PasswordChangeInfo) error diff --git a/backend/utils/mysql/client/info.go b/backend/utils/mysql/client/info.go index 58455adcc..0c05951b6 100644 --- a/backend/utils/mysql/client/info.go +++ b/backend/utils/mysql/client/info.go @@ -4,9 +4,7 @@ import ( "crypto/tls" "crypto/x509" "errors" - "strings" - "github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/go-sql-driver/mysql" ) @@ -103,28 +101,6 @@ var formatMap = map[string]string{ "big5": "big5_chinese_ci", } -func loadNameByDB(name, version string) string { - nameItem := common.ConvertToPinyin(name) - if strings.HasPrefix(version, "5.6") { - if len(nameItem) <= 16 { - return nameItem - } - return strings.TrimSuffix(nameItem[:10], "_") + "_" + common.RandStr(5) - } - if len(nameItem) <= 32 { - return nameItem - } - return strings.TrimSuffix(nameItem[:25], "_") + "_" + common.RandStr(5) -} - -func randomPassword(user string) string { - passwdItem := user - if len(user) > 6 { - passwdItem = user[:6] - } - return passwdItem + "@" + common.RandStrAndNum(8) -} - func VerifyPeerCertFunc(pool *x509.CertPool) func([][]byte, [][]*x509.Certificate) error { return func(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) == 0 { diff --git a/backend/utils/mysql/client/local.go b/backend/utils/mysql/client/local.go index 8c0b7a52c..96711b382 100644 --- a/backend/utils/mysql/client/local.go +++ b/backend/utils/mysql/client/local.go @@ -307,19 +307,6 @@ func (r *Local) SyncDB(version string) ([]SyncDBInfo, error) { } } if len(dataItem.Username) == 0 { - dataItem.Username = loadNameByDB(parts[0], version) - dataItem.Password = randomPassword(dataItem.Username) - if err := r.CreateUser(CreateInfo{ - Name: parts[0], - Format: parts[1], - Version: version, - Username: dataItem.Username, - Password: dataItem.Password, - Permission: "%", - Timeout: 300, - }, false); err != nil { - global.LOG.Errorf("sync from remote server failed, err: create user failed %v", err) - } dataItem.Permission = "%" } else { if isLocal { diff --git a/backend/utils/mysql/client/remote.go b/backend/utils/mysql/client/remote.go index 18a0b01f7..d385b2b47 100644 --- a/backend/utils/mysql/client/remote.go +++ b/backend/utils/mysql/client/remote.go @@ -333,19 +333,6 @@ func (r *Remote) SyncDB(version string) ([]SyncDBInfo, error) { i++ } if len(dataItem.Username) == 0 { - dataItem.Username = loadNameByDB(dbName, version) - dataItem.Password = randomPassword(dataItem.Username) - if err := r.CreateUser(CreateInfo{ - Name: dbName, - Format: charsetName, - Version: version, - Username: dataItem.Username, - Password: dataItem.Password, - Permission: "%", - Timeout: 300, - }, false); err != nil { - return datas, fmt.Errorf("sync db from remote server failed, err: create user failed %v", err) - } dataItem.Permission = "%" } else { if isLocal { diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 67f05d522..d288e5828 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -3952,6 +3952,49 @@ const docTemplate = `{ } } }, + "/databases/bind": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "绑定 mysql 数据库用户", + "consumes": [ + "application/json" + ], + "tags": [ + "Database Mysql" + ], + "summary": "Bind user of mysql database", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.BindUser" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "database", + "username" + ], + "formatEN": "bind mysql database [database] [username]", + "formatZH": "绑定 mysql 数据库名 [database] [username]", + "paramKeys": [] + } + } + }, "/databases/change/access": { "post": { "security": [ @@ -10013,7 +10056,7 @@ const docTemplate = `{ "bodyKeys": [ "version" ], - "formatEN": "upgrade service =\u003e [version]", + "formatEN": "upgrade system =\u003e [version]", "formatZH": "更新系统 =\u003e [version]", "paramKeys": [] } @@ -13601,6 +13644,33 @@ const docTemplate = `{ } } }, + "dto.BindUser": { + "type": "object", + "required": [ + "database", + "db", + "password", + "permission", + "username" + ], + "properties": { + "database": { + "type": "string" + }, + "db": { + "type": "string" + }, + "password": { + "type": "string" + }, + "permission": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, "dto.CaptchaResponse": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 0e5aebd82..5ef899b02 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -3945,6 +3945,49 @@ } } }, + "/databases/bind": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "绑定 mysql 数据库用户", + "consumes": [ + "application/json" + ], + "tags": [ + "Database Mysql" + ], + "summary": "Bind user of mysql database", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.BindUser" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "database", + "username" + ], + "formatEN": "bind mysql database [database] [username]", + "formatZH": "绑定 mysql 数据库名 [database] [username]", + "paramKeys": [] + } + } + }, "/databases/change/access": { "post": { "security": [ @@ -10006,7 +10049,7 @@ "bodyKeys": [ "version" ], - "formatEN": "upgrade service =\u003e [version]", + "formatEN": "upgrade system =\u003e [version]", "formatZH": "更新系统 =\u003e [version]", "paramKeys": [] } @@ -13594,6 +13637,33 @@ } } }, + "dto.BindUser": { + "type": "object", + "required": [ + "database", + "db", + "password", + "permission", + "username" + ], + "properties": { + "database": { + "type": "string" + }, + "db": { + "type": "string" + }, + "password": { + "type": "string" + }, + "permission": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, "dto.CaptchaResponse": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 26c908338..f0d01437b 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -137,6 +137,25 @@ definitions: - bindAddress - ipv6 type: object + dto.BindUser: + properties: + database: + type: string + db: + type: string + password: + type: string + permission: + type: string + username: + type: string + required: + - database + - db + - password + - permission + - username + type: object dto.CaptchaResponse: properties: captchaID: @@ -7268,6 +7287,34 @@ paths: summary: Load mysql base info tags: - Database Mysql + /databases/bind: + post: + consumes: + - application/json + description: 绑定 mysql 数据库用户 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.BindUser' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Bind user of mysql database + tags: + - Database Mysql + x-panel-log: + BeforeFunctions: [] + bodyKeys: + - database + - username + formatEN: bind mysql database [database] [username] + formatZH: 绑定 mysql 数据库名 [database] [username] + paramKeys: [] /databases/change/access: post: consumes: @@ -11106,7 +11153,7 @@ paths: BeforeFunctions: [] bodyKeys: - version - formatEN: upgrade service => [version] + formatEN: upgrade system => [version] formatZH: 更新系统 => [version] paramKeys: [] /toolbox/clean: diff --git a/frontend/src/api/interface/database.ts b/frontend/src/api/interface/database.ts index 6e3a77e19..c0899ccce 100644 --- a/frontend/src/api/interface/database.ts +++ b/frontend/src/api/interface/database.ts @@ -48,6 +48,13 @@ export namespace Database { permission: string; description: string; } + export interface BindUser { + database: string; + db: string; + username: string; + password: string; + permission: string; + } export interface MysqlLoadDB { from: string; type: string; diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts index c92590c16..1186a3042 100644 --- a/frontend/src/api/modules/database.ts +++ b/frontend/src/api/modules/database.ts @@ -19,6 +19,13 @@ export const addMysqlDB = (params: Database.MysqlDBCreate) => { } return http.post(`/databases`, request); }; +export const bindUser = (params: Database.BindUser) => { + let request = deepCopy(params) as Database.BindUser; + if (request.password) { + request.password = Base64.encode(request.password); + } + return http.post(`/databases/bind`, request); +}; export const loadDBFromRemote = (params: Database.MysqlLoadDB) => { return http.post(`/databases/load`, params); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 1a35f171e..b25236353 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -380,6 +380,7 @@ const message = { 'This port is the exposed port of the container. You need to save the modification separately and restart the container!', loadFromRemote: 'Load from server', + userBind: 'Bind User', loadFromRemoteHelper: 'This action will synchronize the database info on the server to 1Panel, do you want to continue?', passwordHelper: 'Unable to retrieve, please modify', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index 8004bc179..e147f9cb3 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -373,6 +373,7 @@ const message = { confNotFound: '未能找到該應用配置文件,請在應用商店升級該應用至最新版本後重試!', loadFromRemote: '從服務器獲取', + userBind: '綁定使用者', loadFromRemoteHelper: '此操作將同步服務器上數據庫信息到 1Panel,是否繼續?', passwordHelper: '無法獲取密碼,請修改', local: '本地', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 83b710808..2a86c1d04 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -373,6 +373,7 @@ const message = { confNotFound: '未能找到该应用配置文件,请在应用商店升级该应用至最新版本后重试!', loadFromRemote: '从服务器获取', + userBind: '绑定用户', loadFromRemoteHelper: '此操作将同步服务器上数据库信息到 1Panel,是否继续?', passwordHelper: '无法获取密码,请修改', local: '本地', diff --git a/frontend/src/views/database/mysql/bind/index.vue b/frontend/src/views/database/mysql/bind/index.vue new file mode 100644 index 000000000..d3ad0e5fb --- /dev/null +++ b/frontend/src/views/database/mysql/bind/index.vue @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + {{ $t('database.remoteHelper') }} + + + + + + + + {{ $t('commons.button.cancel') }} + + + {{ $t('commons.button.confirm') }} + + + + + + + + + diff --git a/frontend/src/views/database/mysql/index.vue b/frontend/src/views/database/mysql/index.vue index 88bc48b8c..61532f0a5 100644 --- a/frontend/src/views/database/mysql/index.vue +++ b/frontend/src/views/database/mysql/index.vue @@ -124,10 +124,24 @@ - + + + + + {{ row.username }} + + + + + {{ $t('database.userBind') }} + + + + - + - + ********** @@ -154,10 +168,10 @@ - - - {{ $t('database.passwordHelper') }} - + + + {{ $t('database.passwordHelper') }} + @@ -221,6 +235,7 @@ + @@ -235,6 +250,7 @@