1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-02-08 01:20:07 +08:00

fix: 解决数据库用户指定多个 ip 无效的问题 (#1019)

This commit is contained in:
ssongliu 2023-05-12 17:48:31 +08:00 committed by GitHub
parent bd2a49e299
commit 7d08875f95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 34 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/model" "github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/buserr" "github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/global"
@ -99,22 +100,7 @@ func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*mode
} }
return nil, err return nil, err
} }
tmpPermission := req.Permission if err := u.createUser(app, req); err != nil {
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user '%s'@'%s' identified by '%s';", req.Username, tmpPermission, req.Password)); err != nil {
_ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", req.Name))
if strings.Contains(err.Error(), "ERROR 1396") {
return nil, buserr.New(constant.ErrUserIsExist)
}
return nil, err
}
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", req.Name, req.Username, tmpPermission)
if req.Name == "*" {
grantStr = fmt.Sprintf("grant all privileges on *.* to '%s'@'%s'", mysql.Username, tmpPermission)
}
if app.Version == "5.7.39" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
}
if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
return nil, err return nil, err
} }
@ -284,24 +270,30 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
} }
if info.Value != mysql.Permission { if info.Value != mysql.Permission {
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", mysql.Username, mysql.Permission)); err != nil { var userlist []string
if strings.Contains(mysql.Permission, ",") {
userlist = strings.Split(mysql.Permission, ",")
} else {
userlist = append(userlist, mysql.Permission)
}
for _, user := range userlist {
if len(user) != 0 {
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists '%s'@'%s'", mysql.Username, user)); err != nil {
return err return err
} }
}
}
if info.ID == 0 { if info.ID == 0 {
return nil return nil
} }
} }
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user if not exists '%s'@'%s' identified by '%s';", mysql.Username, info.Value, mysql.Password)); err != nil {
return err if err := u.createUser(app, dto.MysqlDBCreate{
} Username: mysql.Username,
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value) Name: mysql.Name,
if mysql.Name == "*" { Permission: info.Value,
grantStr = fmt.Sprintf("grant all privileges on *.* to '%s'@'%s'", mysql.Username, info.Value) Password: mysql.Password,
} }); err != nil {
if app.Version == "5.7.39" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
}
if err := excuteSql(app.ContainerName, app.Password, grantStr); err != nil {
return err return err
} }
if err := excuteSql(app.ContainerName, app.Password, "flush privileges"); err != nil { if err := excuteSql(app.ContainerName, app.Password, "flush privileges"); err != nil {
@ -475,6 +467,50 @@ func (u *MysqlService) LoadStatus() (*dto.MysqlStatus, error) {
return &info, nil return &info, nil
} }
func (u *MysqlService) createUser(app *repo.RootInfo, req dto.MysqlDBCreate) error {
var userlist []string
if strings.Contains(req.Permission, ",") {
ips := strings.Split(req.Permission, ",")
for _, ip := range ips {
if len(ip) != 0 {
userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", req.Username, ip))
}
}
} else {
userlist = append(userlist, fmt.Sprintf("'%s'@'%s'", req.Username, req.Permission))
}
for _, user := range userlist {
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("create user %s identified by '%s';", user, req.Password)); err != nil {
handleCreateError(req.Name, userlist, app)
if strings.Contains(err.Error(), "ERROR 1396") {
return buserr.New(constant.ErrUserIsExist)
}
return err
}
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to %s", req.Name, user)
if req.Name == "*" {
grantStr = fmt.Sprintf("grant all privileges on *.* to %s", user)
}
if app.Version == "5.7.39" {
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, req.Password)
}
if err := excSQL(app.ContainerName, app.Password, grantStr); err != nil {
handleCreateError(req.Name, userlist, app)
return err
}
}
return nil
}
func handleCreateError(dbName string, userlist []string, app *repo.RootInfo) {
_ = excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop database `%s`", dbName))
for _, user := range userlist {
if err := excSQL(app.ContainerName, app.Password, fmt.Sprintf("drop user if exists %s", user)); err != nil {
global.LOG.Errorf("drop user failed, err: %v", err)
}
}
}
func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) { func excuteSqlForMaps(containerName, password, command string) (map[string]string, error) {
cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command) cmd := exec.Command("docker", "exec", containerName, "mysql", "-uroot", "-p"+password, "-e", command)
stdout, err := cmd.CombinedOutput() stdout, err := cmd.CombinedOutput()

View File

@ -300,7 +300,7 @@ const message = {
loadBackup: 'Import', loadBackup: 'Import',
setting: 'Settings', setting: 'Settings',
remoteAccess: 'Remote access', remoteAccess: 'Remote access',
remoteHelper: 'One in a row, for example:\n172.16.10.111\n172.16.10.112', remoteHelper: 'Multiple IP comma-delimited, example: 172.16.10.111, 172.16.10.112',
remoteConnHelper: remoteConnHelper:
'Remote connection to mysql as user root may have security risks. Therefore, perform this operation with caution.', 'Remote connection to mysql as user root may have security risks. Therefore, perform this operation with caution.',
changePassword: 'Password', changePassword: 'Password',

View File

@ -314,7 +314,7 @@ const message = {
loadBackup: '导入备份', loadBackup: '导入备份',
setting: '设置', setting: '设置',
remoteAccess: '远程访问', remoteAccess: '远程访问',
remoteHelper: '一行一个\n172.16.10.111\n172.16.10.112', remoteHelper: '多个 ip 以逗号分隔172.16.10.111,172.16.10.112',
remoteConnHelper: 'root 帐号远程连接 mysql 有安全风险开启需谨慎', remoteConnHelper: 'root 帐号远程连接 mysql 有安全风险开启需谨慎',
changePassword: '改密', changePassword: '改密',
changePasswordHelper: '当前数据库已经关联应用修改密码将同步修改应用中数据库密码修改后重启生效', changePasswordHelper: '当前数据库已经关联应用修改密码将同步修改应用中数据库密码修改后重启生效',

View File

@ -37,7 +37,13 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="form.permission === 'ip'" prop="permissionIPs"> <el-form-item v-if="form.permission === 'ip'" prop="permissionIPs">
<el-input clearable v-model="form.permissionIPs" /> <el-input
clearable
:autosize="{ minRows: 2, maxRows: 5 }"
type="textarea"
v-model="form.permissionIPs"
/>
<span class="input-help">{{ $t('database.remoteHelper') }}</span>
</el-form-item> </el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description"> <el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="form.description" /> <el-input type="textarea" clearable v-model="form.description" />
@ -131,6 +137,10 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
createVisiable.value = false; createVisiable.value = false;
}) })
.catch(() => { .catch(() => {
if (form.permission != '%') {
form.permissionIPs = form.permission;
form.permission = 'ip';
}
loading.value = false; loading.value = false;
}); });
}); });

View File

@ -38,12 +38,12 @@
:rules="Rules.requiredInput" :rules="Rules.requiredInput"
> >
<el-input <el-input
:placeholder="$t('database.remoteHelper')"
clearable clearable
:autosize="{ minRows: 2, maxRows: 5 }" :autosize="{ minRows: 2, maxRows: 5 }"
type="textarea" type="textarea"
v-model="changeForm.privilegeIPs" v-model="changeForm.privilegeIPs"
/> />
<span class="input-help">{{ $t('database.remoteHelper') }}</span>
</el-form-item> </el-form-item>
</div> </div>
</el-col> </el-col>
@ -158,7 +158,7 @@ const submitChangeInfo = async (formEl: FormInstance | undefined) => {
if (changeForm.privilege !== 'ip') { if (changeForm.privilege !== 'ip') {
param.value = changeForm.privilege; param.value = changeForm.privilege;
} else { } else {
param.value = changeForm.privilegeIPs.replaceAll('/n', ','); param.value = changeForm.privilegeIPs;
} }
loading.value = true; loading.value = true;
await updateMysqlAccess(param) await updateMysqlAccess(param)