refactor(admin): 开源版移除异常登录检测配置页(转商业版)

This commit is contained in:
DaxPay Dev
2026-07-12 11:37:17 +08:00
parent 3140c49ba1
commit b9e55e2224
5 changed files with 2 additions and 560 deletions

View File

@@ -60,18 +60,6 @@ export const SecurityApi = {
updateTwoFactorAuthConfig(data: TwoFactorAuthConfig): Promise<Result<void>> {
return defHttp.post({ url: '/platform/config/security/two-factor-auth/update', data });
},
/**
* 获取异常登录检测配置
*/
getAnomalyDetectionConfig(): Promise<Result<AnomalyDetectionConfig>> {
return defHttp.get({ url: '/platform/config/security/anomaly-detection/get' });
},
/**
* 更新异常登录检测配置
*/
updateAnomalyDetectionConfig(data: AnomalyDetectionConfig): Promise<Result<void>> {
return defHttp.post({ url: '/platform/config/security/anomaly-detection/update', data });
},
};
/**
@@ -131,6 +119,8 @@ export interface SessionManagementConfig {
enabled?: boolean;
/** 最大在线时长(小时) */
maxOnlineHours?: number;
/** 最大活跃时长小时0表示不限制 */
activeTimeoutHours?: number;
/** 最大并发会话数 */
maxConcurrentSessions?: number;
/** 并发策略 */
@@ -148,23 +138,3 @@ export interface TwoFactorAuthConfig {
/** 备用码数量 */
backupCodesCount?: number;
}
/**
* 异常登录检测配置
*/
export interface AnomalyDetectionConfig {
/** 是否启用 */
enabled?: boolean;
/** 是否检测异常IP */
detectAnomalousIp?: boolean;
/** IP风险阈值 */
ipRiskThreshold?: number;
/** 是否检测异常时间 */
detectAnomalousTime?: boolean;
/** 时间偏差阈值 */
timeDeviationThreshold?: number;
/** 是否检测异常设备 */
detectAnomalousDevice?: boolean;
/** 检测到异常时是否阻止 */
blockOnAnomaly?: boolean;
}

View File

@@ -1,53 +0,0 @@
{
"title": "Anomaly Detection",
"description": "Detect and block anomalous login behaviors",
"summary": {
"enabled": "Detection enabled",
"disabled": "Detection disabled",
"ipDetectionEnabled": "IP detection enabled, threshold {threshold} points",
"ipDetectionDisabled": "IP detection disabled",
"timeDetectionEnabled": "Time detection enabled, deviation threshold {hours} hours",
"timeDetectionDisabled": "Time detection disabled",
"deviceDetectionEnabled": "Device detection enabled",
"deviceDetectionDisabled": "Device detection disabled",
"blockEnabled": "Anomalous login will be blocked",
"blockDisabled": "Anomalous login will only alert"
},
"section": {
"basic": "Basic Settings",
"ipDetection": "IP Detection",
"timeDetection": "Time Detection",
"deviceDetection": "Device Detection",
"blockStrategy": "Block Strategy"
},
"enabled": {
"label": "Enable Anomaly Detection",
"desc": "When enabled, the system will detect anomalous login behaviors."
},
"detectAnomalousIp": {
"label": "Detect Anomalous IP",
"desc": "Detect if login IP has risks, such as proxy IP or high-risk regions."
},
"ipRiskThreshold": {
"label": "IP Risk Threshold",
"desc": "IP risk score above this threshold is considered anomalous.",
"placeholder": "Enter IP risk threshold"
},
"detectAnomalousTime": {
"label": "Detect Anomalous Login Time",
"desc": "Detect if login time deviates from user's typical login hours."
},
"timeDeviationThreshold": {
"label": "Time Deviation Threshold",
"desc": "Login time deviation from user's typical hours above this threshold is considered anomalous.",
"placeholder": "Enter time deviation threshold"
},
"detectAnomalousDevice": {
"label": "Detect Anomalous Device",
"desc": "Detect if login device is user's commonly used device."
},
"blockOnAnomaly": {
"label": "Block on Anomaly",
"desc": "When enabled, anomalous login will be blocked; when disabled, only alerts will be recorded."
}
}

View File

@@ -1,53 +0,0 @@
{
"title": "异常登录检测",
"description": "检测并拦截异常登录行为",
"summary": {
"enabled": "检测已启用",
"disabled": "检测未启用",
"ipDetectionEnabled": "IP检测已启用阈值 {threshold} 分",
"ipDetectionDisabled": "IP检测未启用",
"timeDetectionEnabled": "时间检测已启用,偏离阈值 {hours} 小时",
"timeDetectionDisabled": "时间检测未启用",
"deviceDetectionEnabled": "设备检测已启用",
"deviceDetectionDisabled": "设备检测未启用",
"blockEnabled": "异常登录将拦截",
"blockDisabled": "异常登录仅告警"
},
"section": {
"basic": "基础设置",
"ipDetection": "IP检测",
"timeDetection": "时间检测",
"deviceDetection": "设备检测",
"blockStrategy": "拦截策略"
},
"enabled": {
"label": "启用异常登录检测",
"desc": "开启后,系统将检测异常登录行为。"
},
"detectAnomalousIp": {
"label": "检测异常IP",
"desc": "检测登录IP是否存在风险如代理IP、高风险地区等。"
},
"ipRiskThreshold": {
"label": "IP风险阈值",
"desc": "IP风险评分超过该阈值时视为异常。",
"placeholder": "请输入IP风险阈值"
},
"detectAnomalousTime": {
"label": "检测异常登录时间",
"desc": "检测登录时间是否偏离用户习惯的登录时段。"
},
"timeDeviationThreshold": {
"label": "登录时间偏离阈值",
"desc": "登录时间偏离用户习惯时段超过该阈值时视为异常。",
"placeholder": "请输入时间偏离阈值"
},
"detectAnomalousDevice": {
"label": "检测异常设备",
"desc": "检测登录设备是否为用户常用设备。"
},
"blockOnAnomaly": {
"label": "检测到异常登录时拦截",
"desc": "开启后,检测到异常登录将直接拦截;关闭则仅记录告警。"
}
}

View File

@@ -3,7 +3,6 @@
import { $t } from '#/locales';
import AnomalyDetection from './components/AnomalyDetection.vue';
import LoginSecurity from './components/LoginSecurity.vue';
import PasswordPolicy from './components/PasswordPolicy.vue';
import SessionManagement from './components/SessionManagement.vue';
@@ -28,13 +27,6 @@
// 登录安全描述
description: $t('system.security.login-security.description'),
},
{
key: 'anomalyDetection',
// 异常登录检测标题
label: $t('system.security.anomaly-detection.title'),
// 异常登录检测描述
description: $t('system.security.anomaly-detection.description'),
},
{
key: 'sessionManagement',
// 会话管理标题
@@ -80,7 +72,6 @@
<div class="security-content__scroll">
<PasswordPolicy v-if="activeKey === 'passwordPolicy'" />
<LoginSecurity v-else-if="activeKey === 'loginSecurity'" />
<AnomalyDetection v-else-if="activeKey === 'anomalyDetection'" />
<SessionManagement v-else-if="activeKey === 'sessionManagement'" />
<TwoFactorAuth v-else-if="activeKey === 'twoFactorAuth'" />
</div>

View File

@@ -1,413 +0,0 @@
<script setup lang="ts">
import type { AnomalyDetectionConfig } from '#/api/system/security.api';
import { computed, onMounted, ref } from 'vue';
import { SecurityApi } from '#/api/system/security.api';
import { useMessage } from '#/hooks/useMessage';
import { $t } from '#/locales';
defineOptions({ name: 'AnomalyDetection' });
const { confirm, message } = useMessage();
const loading = ref(false);
const formRef = ref();
// 编辑状态
const isEditing = ref(false);
const formState = ref<AnomalyDetectionConfig>({} as AnomalyDetectionConfig);
const summaryItems = computed(() => {
return [
// 启用状态
formState.value.enabled
? $t('system.security.anomaly-detection.summary.enabled')
: $t('system.security.anomaly-detection.summary.disabled'),
// IP检测
formState.value.detectAnomalousIp
? $t('system.security.anomaly-detection.summary.ipDetectionEnabled', {
threshold: formState.value.ipRiskThreshold ?? 0,
})
: $t('system.security.anomaly-detection.summary.ipDetectionDisabled'),
// 时间检测
formState.value.detectAnomalousTime
? $t('system.security.anomaly-detection.summary.timeDetectionEnabled', {
hours: formState.value.timeDeviationThreshold ?? 0,
})
: $t('system.security.anomaly-detection.summary.timeDetectionDisabled'),
// 设备检测
formState.value.detectAnomalousDevice
? $t('system.security.anomaly-detection.summary.deviceDetectionEnabled')
: $t('system.security.anomaly-detection.summary.deviceDetectionDisabled'),
// 拦截策略
formState.value.blockOnAnomaly
? $t('system.security.anomaly-detection.summary.blockEnabled')
: $t('system.security.anomaly-detection.summary.blockDisabled'),
];
});
/**
* 加载异常登录检测配置
*/
async function loadConfig() {
loading.value = true;
try {
const { data } = await SecurityApi.getAnomalyDetectionConfig();
formState.value = data;
} finally {
loading.value = false;
}
}
/**
* 进入编辑模式
*/
function handleEdit() {
isEditing.value = true;
}
/**
* 取消编辑
*/
function handleCancel() {
loadConfig();
isEditing.value = false;
}
/**
* 保存异常登录检测配置
*/
function handleSave() {
confirm({
// 确认保存
title: $t('system.security.common.confirmSave'),
// 确定要保存当前配置吗?
content: $t('system.security.common.confirmSaveContent'),
okText: $t('common.okText'),
cancelText: $t('common.cancelText'),
onOk: async () => {
try {
await formRef.value?.validate();
} catch {
// 校验失败:表单已显示错误提示
return;
}
loading.value = true;
try {
await SecurityApi.updateAnomalyDetectionConfig(formState.value);
// 保存成功提示
message.success($t('common.saveSuccess'));
await loadConfig();
isEditing.value = false;
} finally {
loading.value = false;
}
},
});
}
onMounted(() => {
loadConfig();
});
</script>
<template>
<a-spin :spinning="loading" class="w-full">
<div class="security-module-page">
<div class="module-overview">
<div class="module-overview__header">
<!-- 异常登录检测标题 -->
<div class="module-overview__title">{{ $t('system.security.anomaly-detection.title') }}</div>
<div class="module-actions">
<a-space>
<!-- 非编辑状态显示编辑按钮 -->
<template v-if="!isEditing">
<a-button type="primary" @click="handleEdit">{{ $t('common.edit') }}</a-button>
</template>
<!-- 编辑状态显示取消和确认按钮 -->
<template v-else>
<a-button @click="handleCancel">{{ $t('system.security.common.cancel') }}</a-button>
<a-button type="primary" :loading="loading" @click="handleSave">{{
$t('system.security.common.confirm')
}}</a-button>
</template>
</a-space>
</div>
</div>
<!-- 异常登录检测描述 -->
<div class="module-overview__desc">{{ $t('system.security.anomaly-detection.description') }}</div>
<a-space wrap size="small" class="module-overview__tags">
<a-tag v-for="item in summaryItems" :key="item">{{ item }}</a-tag>
</a-space>
</div>
<a-form ref="formRef" :model="formState" layout="vertical" class="module-form">
<div class="config-section">
<!-- 基础设置 -->
<div class="config-section__title">{{ $t('system.security.anomaly-detection.section.basic') }}</div>
<div class="config-item">
<div class="config-item__main">
<!-- 启用异常登录检测标签 -->
<div class="config-item__label">{{ $t('system.security.anomaly-detection.enabled.label') }}</div>
<!-- 启用异常登录检测描述 -->
<div class="config-item__desc">{{ $t('system.security.anomaly-detection.enabled.desc') }}</div>
</div>
<a-switch v-model:checked="formState.enabled" :disabled="!isEditing" />
</div>
</div>
<div class="config-section">
<!-- IP检测 -->
<div class="config-section__title">{{ $t('system.security.anomaly-detection.section.ipDetection') }}</div>
<div class="config-grid">
<div class="config-item">
<div class="config-item__main">
<!-- 检测异常IP标签 -->
<div class="config-item__label">{{
$t('system.security.anomaly-detection.detectAnomalousIp.label')
}}</div>
<!-- 检测异常IP描述 -->
<div class="config-item__desc">{{
$t('system.security.anomaly-detection.detectAnomalousIp.desc')
}}</div>
</div>
<a-switch v-model:checked="formState.detectAnomalousIp" :disabled="!isEditing" />
</div>
<div class="config-item config-item--block">
<div class="config-item__main">
<!-- IP风险阈值标签 -->
<div class="config-item__label">{{
$t('system.security.anomaly-detection.ipRiskThreshold.label')
}}</div>
<!-- IP风险阈值描述 -->
<div class="config-item__desc">{{ $t('system.security.anomaly-detection.ipRiskThreshold.desc') }}</div>
</div>
<div class="number-field">
<!-- 国际化请输入IP风险阈值 -->
<a-input-number
v-model:value="formState.ipRiskThreshold"
:min="0"
:max="100"
:placeholder="$t('system.security.anomaly-detection.ipRiskThreshold.placeholder')"
:disabled="!isEditing"
style="width: 180px"
/>
<!-- 单位 -->
<span class="number-field__suffix">{{ $t('system.security.common.unit.score') }}</span>
</div>
</div>
</div>
</div>
<div class="config-section">
<!-- 时间检测 -->
<div class="config-section__title">{{ $t('system.security.anomaly-detection.section.timeDetection') }}</div>
<div class="config-grid">
<div class="config-item">
<div class="config-item__main">
<!-- 检测异常登录时间标签 -->
<div class="config-item__label">{{
$t('system.security.anomaly-detection.detectAnomalousTime.label')
}}</div>
<!-- 检测异常登录时间描述 -->
<div class="config-item__desc">{{
$t('system.security.anomaly-detection.detectAnomalousTime.desc')
}}</div>
</div>
<a-switch v-model:checked="formState.detectAnomalousTime" :disabled="!isEditing" />
</div>
<div class="config-item config-item--block">
<div class="config-item__main">
<!-- 登录时间偏离阈值标签 -->
<div class="config-item__label">{{
$t('system.security.anomaly-detection.timeDeviationThreshold.label')
}}</div>
<!-- 登录时间偏离阈值描述 -->
<div class="config-item__desc">{{
$t('system.security.anomaly-detection.timeDeviationThreshold.desc')
}}</div>
</div>
<div class="number-field">
<!-- 国际化请输入时间偏离阈值 -->
<a-input-number
v-model:value="formState.timeDeviationThreshold"
:min="1"
:max="24"
:placeholder="$t('system.security.anomaly-detection.timeDeviationThreshold.placeholder')"
:disabled="!isEditing"
style="width: 180px"
/>
<!-- 单位小时 -->
<span class="number-field__suffix">{{ $t('system.security.common.unit.hour') }}</span>
</div>
</div>
</div>
</div>
<div class="config-section">
<!-- 设备检测 -->
<div class="config-section__title">{{ $t('system.security.anomaly-detection.section.deviceDetection') }}</div>
<div class="config-item">
<div class="config-item__main">
<!-- 检测异常设备标签 -->
<div class="config-item__label">{{
$t('system.security.anomaly-detection.detectAnomalousDevice.label')
}}</div>
<!-- 检测异常设备描述 -->
<div class="config-item__desc">{{
$t('system.security.anomaly-detection.detectAnomalousDevice.desc')
}}</div>
</div>
<a-switch v-model:checked="formState.detectAnomalousDevice" :disabled="!isEditing" />
</div>
</div>
<div class="config-section">
<!-- 拦截策略 -->
<div class="config-section__title">{{ $t('system.security.anomaly-detection.section.blockStrategy') }}</div>
<div class="config-item">
<div class="config-item__main">
<!-- 检测到异常登录时拦截标签 -->
<div class="config-item__label">{{ $t('system.security.anomaly-detection.blockOnAnomaly.label') }}</div>
<!-- 检测到异常登录时拦截描述 -->
<div class="config-item__desc">{{ $t('system.security.anomaly-detection.blockOnAnomaly.desc') }}</div>
</div>
<a-switch v-model:checked="formState.blockOnAnomaly" :disabled="!isEditing" />
</div>
</div>
</a-form>
</div>
</a-spin>
</template>
<style scoped>
.security-module-page {
display: flex;
flex-direction: column;
gap: 16px;
padding-top: 4px;
}
.module-overview {
display: flex;
flex-direction: column;
gap: 10px;
}
.module-overview__header {
display: flex;
gap: 16px;
align-items: flex-start;
justify-content: space-between;
}
.module-overview__title {
font-size: 18px;
font-weight: 600;
color: hsl(var(--foreground));
}
.module-overview__desc {
font-size: 13px;
line-height: 1.7;
color: hsl(var(--muted-foreground));
}
.module-overview__tags {
padding-top: 2px;
}
.module-form {
display: flex;
flex-direction: column;
gap: 16px;
}
.config-section {
display: flex;
flex-direction: column;
gap: 12px;
}
.config-section__title {
font-size: 15px;
font-weight: 600;
color: hsl(var(--foreground));
}
.config-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.config-item {
display: flex;
gap: 16px;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
background: hsl(var(--card));
border: 1px solid hsl(var(--border));
border-radius: 12px;
transition:
border-color 0.2s ease,
box-shadow 0.2s ease;
}
.config-item:hover {
border-color: hsl(var(--primary) / 30%);
box-shadow: 0 1px 2px rgb(15 23 42 / 4%);
}
.config-item--block {
flex-direction: column;
align-items: flex-start;
}
.config-item--full {
grid-column: span 2;
}
.config-item__main {
flex: 1;
min-width: 0;
}
.config-item__label {
font-size: 14px;
font-weight: 500;
color: hsl(var(--foreground));
}
.config-item__desc {
margin-top: 4px;
font-size: 12px;
line-height: 1.6;
color: hsl(var(--muted-foreground));
}
.number-field {
display: inline-flex;
gap: 8px;
align-items: center;
}
.number-field__suffix {
flex: 0 0 auto;
font-size: 13px;
color: hsl(var(--muted-foreground));
}
.module-actions {
flex-shrink: 0;
}
</style>