Skip to content

Commit

Permalink
feat(frontend): 密码规则校验 TencentBlueKing#7031
Browse files Browse the repository at this point in the history
# Reviewed, transaction id: 20130
  • Loading branch information
JustaCattt committed Oct 10, 2024
1 parent 0369e63 commit d4280b5
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 138 deletions.
7 changes: 5 additions & 2 deletions dbm-ui/frontend/src/locales/zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -1046,10 +1046,10 @@
"清除表数据和结构_droptable": "清除表数据和结构(drop table)",
"清除表数据_truncatetable": "清除表数据(truncate table)",
"特殊符号序": "特殊符号序",
"包含特殊字符_除空格外": "包含特殊字符,除空格外",
"包含数字": "包含数字",
"包含大写字母": "包含大写字母",
"包含小写字母": "包含小写字母",
"指定特殊字符(s)": "包含指定特殊字符({s})",
"MySQL_授权规则": "【MySQL】授权规则",
"MySQL主从集群_实例详情": "【MySQL 主从集群】实例详情",
"MySQL主从集群_实例视图": "【MySQL 主从集群】实例视图",
Expand Down Expand Up @@ -3531,5 +3531,8 @@
"密码校验": "密码校验",
"包含上述任意": "包含上述任意",
"指定特殊字符": "指定特殊字符",
"这行勿动!新增翻译请在上一行添加!": ""
"这行勿动!新增翻译请在上一行添加!": "",
"包含": "包含",
"中的任意 n 种": "中的任意 {n} 种",
"不允许超过 x 位连续字符": "不允许超过 {x} 位连续字符"
}
11 changes: 5 additions & 6 deletions dbm-ui/frontend/src/services/types/permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,16 @@ export interface PasswordStrength {
* 密码强度校验项
*/
export interface PasswordStrengthVerifyInfo {
number_of_types_valid: boolean;
allowed_valid: boolean;
out_of_range: string;
repeats_valid: boolean;
follow_keyboards_valid: boolean;
follow_letters_valid: boolean;
follow_numbers_valid: boolean;
follow_symbols_valid: boolean;
lowercase_valid: boolean;
max_length_valid: boolean;
min_length_valid: boolean;
numbers_valid: boolean;
repeats_valid: boolean;
symbols_valid: boolean;
uppercase_valid: boolean;
max_length_valid: boolean;
}

// 密码策略
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,11 @@
<div
v-for="(item, index) of passwordState.strength"
:key="index"
class="password-strength__item">
class="password-strength-item">
<span
class="password-strength__status"
class="password-strength-status"
:class="[getStrenthStatus(item)]" />
<span class="password-strength__content">{{ item.text }}</span>
<span class="password-strength-content">{{ item.text }}</span>
</div>
</div>
</div>
Expand All @@ -134,6 +134,7 @@
getRSAPublicKeys,
verifyPasswordStrength,
} from '@services/source/permission';
import type { PasswordPolicyIncludeRule } from '@services/types';

import { useCopy } from '@hooks';

Expand All @@ -142,16 +143,11 @@
import { AccountTypes } from '@common/const';
import { dbTippy } from '@common/tippy';

import { PASSWORD_POLICY, type PasswordPolicyKeys } from '../common/const';

interface StrengthItem {
keys: string[];
text: string;
}

type PasswordPolicy = ServiceReturnType<typeof getPasswordPolicy>;
type IncludeRule = PasswordPolicy['rule']['include_rule'];
type ExcludeContinuousRule = PasswordPolicy['rule']['exclude_continuous_rule'];
type PasswordStrength = ServiceReturnType<typeof verifyPasswordStrength>;
type PasswordStrengthVerifyInfo = PasswordStrength['password_verify_info'];

Expand Down Expand Up @@ -186,26 +182,10 @@
return passwordStrengthResult.is_strength;
});

/**
* 拆分是否带有follow_前缀的keys
*/
const keyArr = Object.keys(PASSWORD_POLICY).reduce<{ included: string[]; excluded: string[] }>(
(acc, key) => {
if (key.includes('follow_')) {
acc.included.push(key);
} else {
acc.excluded.push(key);
}
return acc;
},
{ included: [], excluded: [] },
);
const passwordState = reactive({
instance: null as Instance | null,
isShow: false,
strength: [] as StrengthItem[],
keys: keyArr.excluded,
followKeys: keyArr.included,
validate: {} as PasswordStrength,
});
const state = reactive({
Expand Down Expand Up @@ -301,58 +281,55 @@
* 获取密码安全策略
*/
const fetchPasswordPolicy = () => {
getPasswordPolicy().then((passwordPolicyResult) => {
getPasswordPolicy({
name: 'mysql_password',
}).then((passwordPolicyResult) => {
const {
repeats,
min_length: minLength,
max_length: maxLength,
include_rule: includeRule,
exclude_continuous_rule: excludeContinuousRule,
weak_password: weakPassword,
number_of_types: numberOfType,
symbols_allowed: symbolsAllowed,
} = passwordPolicyResult.rule;

const PASSWORD_POLICY = {
lowercase: '小写字母',
uppercase: '大写字母',
numbers: '数字',
symbols: '指定特殊字符(s)',
};

const texts = Object.entries(PASSWORD_POLICY).map(([key, text]) => {
const valid = includeRule[key as keyof PasswordPolicyIncludeRule];

if (!valid) {
return '';
}

if (key === 'symbols') {
return t(text, { s: symbolsAllowed });
}

return t(text);
});

passwordState.strength = [
{
keys: ['min_length_valid', 'max_length_valid'],
text: t('密码长度为_min_max', [minLength, maxLength]),
},
{
keys: ['number_of_types_valid'],
text: t('包含') + texts.join('、') + t('中的任意 n 种', { n: numberOfType }),
},
];
// 常规提示
for (const key of passwordState.keys) {
if (includeRule[key as keyof IncludeRule]) {
passwordState.strength.push({
keys: [`${key}_valid`],
text: t(PASSWORD_POLICY[key as PasswordPolicyKeys]),
});
}
}

// 重复提示
if (excludeContinuousRule.repeats) {
passwordState.strength.push({
keys: ['repeats_valid'],
text: t('不能连续重复n位字母_数字_特殊符号', { n: excludeContinuousRule.limit }),
});
}

// 特殊提示(键盘序、字符序、数字序等)
const special = passwordState.followKeys.reduce<StrengthItem[]>((values: StrengthItem[], key: string) => {
const valueKey = key.replace('follow_', '') as keyof ExcludeContinuousRule;
if (excludeContinuousRule[valueKey]) {
values.push({
keys: [`${key}_valid`],
text: t(PASSWORD_POLICY[key as PasswordPolicyKeys]),
});
}
return values;
}, []);
if (special.length > 0) {
const keys: string[] = [];
const texts: string[] = [];
for (const item of special) {
keys.push(...item.keys);
texts.push(item.text);
}
if (weakPassword) {
passwordState.strength.push({
keys,
text: texts.join('、'),
keys: ['is_strength'],
text: t('不允许超过 x 位连续字符', { x: repeats }),
});
}

Expand Down Expand Up @@ -403,11 +380,17 @@
return '';
}

const isPass = item.keys.every((key) => {
const verifyInfo = passwordState.validate.password_verify_info || {};
return verifyInfo[key as keyof PasswordStrengthVerifyInfo];
});
return `password-strength__status--${isPass ? 'success' : 'failed'}`;
let isPass = false;
if (item.keys[0] === 'is_strength') {
isPass = passwordState.validate.is_strength;
} else {
isPass = item.keys.every((key) => {
const verifyInfo = passwordState.validate.password_verify_info || {};
return verifyInfo[key as keyof PasswordStrengthVerifyInfo];
});
}

return `password-strength-status--${isPass ? 'success' : 'failed'}`;
};

/**
Expand Down Expand Up @@ -487,12 +470,14 @@
padding-top: 4px;
font-size: @font-size-mini;

&__item {
.password-strength-item {
display: flex;
padding-bottom: 4px;
.flex-center();
}

&__status {
.password-strength-status {
position: relative;
top: 6px;
width: 6px;
height: 6px;
margin-right: 8px;
Expand All @@ -507,5 +492,9 @@
background-color: @bg-danger;
}
}

.password-strength-content {
width: 280px;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@

import { getSearchSelectorParams } from '@utils';

import { dbOperations } from './common/const';
import AccountDialog from './components/AccountDialog.vue';

const { t } = useI18n();
Expand Down Expand Up @@ -171,6 +170,25 @@
const tableSearch = ref([]);
const clusterAuthorizeRef = ref<InstanceType<typeof ClusterAuthorize>>();

const dbOperations = {
dml: ['select', 'insert', 'update', 'delete', 'show view'],
ddl: [
'create',
'alter',
'drop',
'index',
'create view',
'execute',
'trigger',
'event',
'create routine',
'alter routine',
'references',
'create temporary tables',
],
glob: ['file', 'reload', 'show databases', 'process', 'replication slave', 'replication client'],
};

/**
* search select 过滤参数
*/
Expand Down

0 comments on commit d4280b5

Please sign in to comment.