Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(frontend): 权限规则db校验规则 #8407 #8536

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions dbm-ui/frontend/src/locales/zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -641,11 +641,9 @@
"即将删除账号xx_删除后将不能恢复": "即将删除账号\"{name}\", 删除后将不能恢复",
"成功删除账号": "成功删除账号",
"成功添加授权规则": "成功添加授权规则",
"访问DB不能为空": "访问 DB 不能为空",
"请设置权限": "请设置权限",
"全选": "全选",
"权限设置": "权限设置",
"请输入DB名称_可以使用通配符_如Data_区分大小写_多个使用英文逗号_分号或换行分隔": "请输入 DB 名称,可以使用通配符 %,如 Data%,区分大小写,多个使用英文逗号、分号或换行分隔",
"该账号下已存在xx规则": "该账号下已存在 {0} 规则",
"收藏成功": "收藏成功",
"取消收藏成功": "取消收藏成功",
Expand Down Expand Up @@ -3712,5 +3710,9 @@
"请输入访问DB名_以字母开头_支持字母_数字_下划线_多个使用英文逗号_分号或换行分隔": "请输入访问DB名,以字母开头,支持字母,数字,下划线。多个使用英文逗号、分号或换行分隔",
"单据协助设置": "单据协助设置",
"主域名,从域名,单节点必须分开查询": "主域名,从域名,单节点必须分开查询",
"请输入访问DB名_支持 % 通配符_多个使用英文逗号_分号或换行分隔": "请输入访问DB名,支持 % 通配符。多个使用英文逗号、分号或换行分隔",
"% 不能单独使用": "% 不能单独使用",
"访问 DB 名必须合法": "访问 DB 名必须合法",
"请输入访问DB名_以字母开头_支持 % 通配符 或 % 单独使用代表ALL_多个使用英文逗号_分号或换行分隔": "请输入访问DB名,以字母开头,支持 % 通配符 或 % 单独使用代表ALL。多个使用英文逗号、分号或换行分隔",
"这行勿动!新增翻译请在上一行添加!": ""
}
2 changes: 1 addition & 1 deletion dbm-ui/frontend/src/types/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@ declare global {
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
import('vue')
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
ref="ruleRef"
class="rule-form"
form-type="vertical"
:model="formdata"
:model="formData"
:rules="rules">
<BkFormItem
:label="t('账号名')"
property="account_id"
required>
<BkSelect
v-model="formdata.account_id"
v-model="formData.account_id"
:clearable="false"
filterable
:input-search="false"
Expand Down Expand Up @@ -58,7 +58,7 @@
required
:rules="rules.access_db">
<BkInput
v-model="formdata.access_db"
v-model="formData.access_db"
:maxlength="100"
:placeholder="t('请输入访问DB名_以字母开头_支持字母_数字_下划线_多个使用英文逗号_分号或换行分隔')"
:rows="4"
Expand All @@ -67,7 +67,7 @@
<BkFormItem
class="form-item privilege"
:label="t('权限设置')"
property="auth"
property="privilege"
:required="false">
<div class="rule-setting-box">
<BkFormItem
Expand All @@ -82,7 +82,7 @@
{{ t('全选') }}
</BkCheckbox>
<BkCheckboxGroup
v-model="formdata.privilege.mongo_user"
v-model="formData.privilege.mongo_user"
class="checkbox-group">
<BkCheckbox
v-for="option of mongoUserDbOperations"
Expand All @@ -106,7 +106,7 @@
{{ t('全选') }}
</BkCheckbox>
<BkCheckboxGroup
v-model="formdata.privilege.mongo_manager"
v-model="formData.privilege.mongo_manager"
class="checkbox-group">
<BkCheckbox
v-for="option of dbOperations.mongo_manager"
Expand Down Expand Up @@ -138,7 +138,6 @@
</template>

<script setup lang="ts">
import { Message } from 'bkui-vue';
import _ from 'lodash';
import { useI18n } from 'vue-i18n';
import { useRequest } from 'vue-request';
Expand All @@ -152,9 +151,11 @@

import DbForm from '@components/db-form/index.vue';

import { messageSuccess } from '@utils';

import dbOperations from './config';

type AuthItemKey = keyof typeof dbOperations;
type AuthItemKey = 'mongo_user' | 'mongo_manager';

interface Props {
accountId: number;
Expand All @@ -171,9 +172,17 @@
default: false,
});

const { t } = useI18n();
const handleBeforeClose = useBeforeClose();

const ruleRef = ref<InstanceType<typeof DbForm>>();
const accounts = ref<PermissionRuleAccount[]>([]);
const existDBs = ref<string[]>([]);
const accessDBType = ref<'admin' | 'not_admin'>('admin');

const replaceReg = /[,;\r\n]/g;

const initFormdata = () => ({
const initFormData = () => ({
account_id: -1,
access_db: 'admin',
privilege: {
Expand All @@ -182,47 +191,13 @@
},
});

const verifyAccountRulesExits = () => {
existDBs.value = [];

const user = selectedUserInfo.value?.user;
const dbs = formdata.value.access_db
.replace(replaceReg, ',')
.split(',')
.filter((db) => db !== '');

if (!user || dbs.length === 0) {
return false;
}

return queryAccountRules({
user,
access_dbs: dbs,
account_type: AccountTypes.MONGODB,
}).then((res) => {
const rules = res.results[0]?.rules || [];
existDBs.value = rules.map((item) => item.access_db);

return rules.length === 0;
});
};

const { t } = useI18n();
const handleBeforeClose = useBeforeClose();

const ruleRef = ref<InstanceType<typeof DbForm>>();
const formdata = ref(initFormdata());
const accounts = ref<PermissionRuleAccount[]>([]);
const existDBs = ref<string[]>([]);
const accessDBType = ref<'admin' | 'not_admin'>('admin');

const rules = {
auth: [
privilege: [
{
trigger: 'change',
message: t('请设置权限'),
validator: () => {
const { mongo_user: mongoUser, mongo_manager: mongoManager } = formdata.value.privilege;
const { mongo_user: mongoUser, mongo_manager: mongoManager } = formData.privilege;
return mongoUser.length !== 0 || mongoManager.length !== 0;
},
},
Expand All @@ -232,12 +207,35 @@
required: true,
trigger: 'blur',
message: t('访问 DB 不能为空'),
validator: (value: string) => !!value,
validator: (value: string) => {
const dbs = value.split(/[\n;,]/);
return _.every(dbs, (item) => !!item.trim());
},
},
{
required: true,
trigger: 'blur',
message: () => t('该账号下已存在xx规则', [existDBs.value.join(',')]),
validator: verifyAccountRulesExits,
message: () => t('该账号下已存在xx规则', [existDBs.value.join(',')]),
validator: () => {
existDBs.value = [];
const user = accounts.value.find((item) => item.account_id === formData.account_id)?.user;
const dbs = formData.access_db
.replace(replaceReg, ',')
.split(',')
.filter((db) => db !== '');
if (!user || dbs.length === 0) {
return false;
}
return queryAccountRules({
user,
access_dbs: dbs,
account_type: AccountTypes.MONGODB,
}).then((res) => {
const rules = res.results[0]?.rules || [];
existDBs.value = rules.map((item) => item.access_db);
return rules.length === 0;
});
},
},
{
required: true,
Expand All @@ -251,40 +249,38 @@
message: t('请输入访问DB名_以字母开头_支持字母_数字_下划线_多个使用英文逗号_分号或换行分隔'),
validator: (value: string) => {
const dbs = value.split(/[\n;,]/);
return _.every(dbs, (item) => (!item ? true : /^[_a-zA-Z0-9]/.test(item) && !/\*/.test(value)));
return _.every(dbs, (item) => (!item ? true : /^(?:[a-zA-Z].*$)/.test(item)));
},
},
],
};

const selectedUserInfo = computed(() => accounts.value.find((item) => item.account_id === formdata.value.account_id));
const formData = reactive(initFormData());

const mongoUserDbOperations = computed(() =>
accessDBType.value === 'not_admin' ? ['read', 'readWrite'] : dbOperations.mongo_user,
);

const { loading: isSubmitting, run: addMongodbAccountRuleRun } = useRequest(addAccountRule, {
const { run: getPermissionRulesRun, loading: getPermissionRulesLoading } = useRequest(getPermissionRules, {
manual: true,
onSuccess() {
Message({
message: t('成功添加授权规则'),
theme: 'success',
});
emits('success');
window.changeConfirm = false;
handleClose();
onSuccess(permissionRules) {
accounts.value = permissionRules.results.map((item) => item.account);
},
});

const { run: getPermissionRulesRun, loading: getPermissionRulesLoading } = useRequest(getPermissionRules, {
const { run: addMongodbAccountRuleRun, loading: isSubmitting } = useRequest(addAccountRule, {
manual: true,
onSuccess(permissionRules) {
accounts.value = permissionRules.results.map((item) => item.account);
onSuccess() {
messageSuccess(t('成功添加授权规则'));
emits('success');
window.changeConfirm = false;
handleClose();
},
});

watch(isShow, (show) => {
if (show) {
formdata.value.account_id = props.accountId ?? -1;
formData.account_id = props.accountId ?? -1;
getPermissionRulesRun({
offset: 0,
limit: -1,
Expand All @@ -293,24 +289,24 @@
}
});

const getAllCheckedboxValue = (key: AuthItemKey) => formdata.value.privilege[key].length === dbOperations[key].length;
const getAllCheckedboxValue = (key: AuthItemKey) => formData.privilege[key].length === dbOperations[key].length;

const getAllCheckedboxIndeterminate = (key: AuthItemKey) =>
formdata.value.privilege[key].length > 0 && formdata.value.privilege[key].length !== dbOperations[key].length;
formData.privilege[key].length > 0 && formData.privilege[key].length !== dbOperations[key].length;

const handleSelectedAll = (key: AuthItemKey, value: boolean) => {
if (value) {
formdata.value.privilege[key] = dbOperations[key];
formData.privilege[key] = dbOperations[key];
return;
}

formdata.value.privilege[key] = [];
formData.privilege[key] = [];
};

const handleAccessDBTypeChange = (value: 'admin' | 'not_admin') => {
formdata.value.access_db = value === 'admin' ? 'admin' : '';
formdata.value.privilege.mongo_user = [];
formdata.value.privilege.mongo_manager = [];
formData.access_db = value === 'admin' ? 'admin' : '';
formData.privilege.mongo_user = [];
formData.privilege.mongo_manager = [];
};

const handleClose = async () => {
Expand All @@ -321,7 +317,7 @@
}

isShow.value = false;
formdata.value = initFormdata();
_.merge(formData, initFormData());
accessDBType.value = 'admin';
existDBs.value = [];
window.changeConfirm = false;
Expand All @@ -330,8 +326,8 @@
const handleSubmit = async () => {
await ruleRef.value!.validate();
const params = {
...formdata.value,
access_db: formdata.value.access_db.replace(replaceReg, ','), // 统一分隔符
...formData,
access_db: formData.access_db.replace(replaceReg, ','), // 统一分隔符
account_type: AccountTypes.MONGODB,
};
addMongodbAccountRuleRun(params);
Expand Down
Loading
Loading