Skip to content
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
4 changes: 2 additions & 2 deletions ui/src/views/VIEW_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,8 @@ View 负责路由、资源与模式、图加载、保存/发布/调试编排
预览组件位于 `display-setting/components/`,通过 Props 接收名称、展示草稿和临时图片地址,
在组件内部合并图片地址;临时 URL 的创建和释放由弹窗负责。
展示配置保存协议及后端支持情况见 API 文档。
访问限制位于本地 `access-restriction/`,入口按 `auth.isCE` 选择社区版 `AccessRestrictionDrawer.vue`,
其他版本使用 `XpackAccessRestrictionDrawer.vue`;按需挂载,关闭动画后卸载。
访问限制位于本地 `access-restriction/AccessRestrictionDrawer.vue`,抽屉内部按 `auth.isPE || auth.isEE` 判断商业版,
商业版开启身份认证时展示登录配置;按需挂载,关闭动画后卸载。
每次打开通过当前范围 Application API 查询配置;支持提问次数、登录认证及嵌入白名单,开关只修改草稿,保存时统一提交。
社区版身份认证只有开关,不查询登录方式、不生成登录配置字段,保存时保留已有认证配置。
Xpack 版可用登录方式查询 `/chat_user/auth/types`,开启认证时至少选一种;账号登录的验证码阈值沿用 -1~10。
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
<script setup lang="ts">
import { onMounted, reactive, ref, useTemplateRef } from 'vue'
import { computed, onMounted, reactive, ref, useTemplateRef } from 'vue'
import { cloneDeep } from 'lodash'
import type { FormInstance } from 'element-plus'
import type { ApplicationAuthenticationConfig, ApplicationAccessTokenPayload } from '@/api/types'
import type { FormInstance, FormRules } from 'element-plus'
import ChatUserAuthApi from '@/api/admin/system/chat-management/chat-user-auth'
import { LOGIN_METHOD } from '@/api/enums'
import type { ApplicationAuthenticationConfig, ApplicationAccessTokenPayload, LoginMethod, OptionItem } from '@/api/types'
import { LOGIN_METHOD_LABELS } from '@/constants/auth'
import { useStore } from '@/stores/admin'
import { MsgSuccess } from '@/utils/message'
import { useApplicationDetailContext } from '../../context'

defineOptions({ name: 'AccessRestrictionDrawer' })

const emit = defineEmits<{ closed: [] }>()
const { auth } = useStore()
const { applicationId, resourceApi } = useApplicationDetailContext()
const visible = ref(true)
const loading = ref(false)
const loginMethodOptions = ref<OptionItem<string>[]>([])
const formRef = useTemplateRef<FormInstance>('formRef')
const form = reactive({
language: undefined as string | undefined,
Expand All @@ -22,6 +28,24 @@ const form = reactive({
white_list: '',
})

const defaultLoginMethodOptions = computed(() =>
loginMethodOptions.value.filter((option) => form.authentication_value.login_value?.includes(option.value)),
)
const rules: FormRules<typeof form> = {
'authentication_value.login_value': [{ required: true, type: 'array', min: 1, message: '请选择至少一种登录方式', trigger: 'change' }],
'authentication_value.default_value': [{ required: true, message: '请选择默认登录方式', trigger: 'change' }],
'authentication_value.max_attempts': [{ required: true, type: 'integer', min: -1, max: 10, message: '请输入 -1~10 的整数', trigger: 'change' }],
'authentication_value.failed_attempts': [{ required: true, type: 'integer', min: 1, max: 100, message: '请输入 1~100 的整数', trigger: 'change' }],
'authentication_value.lock_time': [{ required: true, type: 'integer', min: 1, max: 1440, message: '请输入 1~1440 的整数', trigger: 'change' }],
}

function handleLoginMethodsChange() {
const loginMethods = form.authentication_value.login_value ?? []
if (!loginMethods.includes(form.authentication_value.default_value ?? '')) {
form.authentication_value.default_value = loginMethods[0] ?? ''
}
}

function loadAccessRestriction() {
if (loading.value) return
loading.value = true
Expand All @@ -36,6 +60,24 @@ function loadAccessRestriction() {
white_active: config.white_active,
white_list: config.white_list?.join('\n') ?? '',
})
if (auth.isPE || auth.isEE) {
return ChatUserAuthApi.getChatUserAuthType().then((options) => {
loginMethodOptions.value = options
const authConfig = config.authentication_value
form.authentication_value = {
...cloneDeep(authConfig ?? {}),
type: authConfig?.type ?? 'login',
login_value: [
...(authConfig?.login_value ?? (options.some((option) => option.value === LOGIN_METHOD.LOCAL) ? [LOGIN_METHOD.LOCAL] : [])),
],
default_value: authConfig?.default_value ?? '',
max_attempts: authConfig?.max_attempts ?? 1,
failed_attempts: authConfig?.failed_attempts ?? 5,
lock_time: authConfig?.lock_time ?? 10,
}
handleLoginMethodsChange()
})
}
})
.finally(() => {
loading.value = false
Expand Down Expand Up @@ -77,7 +119,7 @@ onMounted(loadAccessRestriction)
<template>
<MkDrawer v-model="visible" title="访问限制" @closed="emit('closed')">
<div v-loading="loading">
<el-form ref="formRef" :model="form" label-position="top" require-asterisk-position="right" @submit.prevent>
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" require-asterisk-position="right" @submit.prevent>
<el-form-item label="每个客户端提问限制">
<el-input-number
v-model="form.access_num"
Expand All @@ -96,14 +138,76 @@ onMounted(loadAccessRestriction)
<template #label>
<span class="flex-align-center gap-1">
身份认证
<MkTooltip content="开启身份认证后,智能体和关联的知识库均需要对话用户授权配置,否则用户无权限登录和知识库检索">
<MkTooltip placement="right" content="开启身份认证后,智能体和关联的知识库均需要对话用户授权配置,否则用户无权限登录和知识库检索">
<MkIcon name="icon_info_outlined" class="text-N600!" />
</MkTooltip>
</span>
</template>
<!-- 设置身份认证 -->
<el-switch v-model="form.authentication" />
</el-form-item>
<template v-if="(auth.isPE || auth.isEE) && form.authentication">
<el-form-item label="登录方式" prop="authentication_value.login_value">
<!-- 选择允许的登录方式 -->
<el-checkbox-group v-model="form.authentication_value.login_value" class="flex-wrap gap-x-6" @change="handleLoginMethodsChange">
<template v-for="option in loginMethodOptions" :key="option.value">
<el-checkbox :value="option.value" :disabled="option.disabled" class="w-32">
{{ LOGIN_METHOD_LABELS[option.value as LoginMethod] || option.label }}
</el-checkbox>
</template>
</el-checkbox-group>
</el-form-item>
<el-form-item label="默认登录方式" prop="authentication_value.default_value">
<el-select v-model="form.authentication_value.default_value" placeholder="请选择默认登录方式">
<template v-for="option in defaultLoginMethodOptions" :key="option.value">
<el-option :value="option.value" :label="LOGIN_METHOD_LABELS[option.value as LoginMethod] || option.label" />
</template>
</el-select>
</el-form-item>
<el-form-item v-if="form.authentication_value.login_value?.includes(LOGIN_METHOD.LOCAL)" label="账号登录验证码设置" required>
<div class="mk-gray-card-lg w-full space-y-4">
<div class="flex-align-center gap-2">
<span class="shrink-0">登录失败</span>
<el-form-item prop="authentication_value.max_attempts" class="mb-0!">
<el-input-number
v-model="form.authentication_value.max_attempts"
class="w-32!"
:min="-1"
:max="10"
:precision="0"
:value-on-clear="1"
/>
</el-form-item>
<span class="shrink-0">次显示验证码</span>
</div>
<div class="flex-align-center gap-2">
<span class="shrink-0">登录失败</span>
<el-form-item prop="authentication_value.failed_attempts" class="mb-0!">
<el-input-number
v-model="form.authentication_value.failed_attempts"
class="w-32!"
:min="1"
:max="100"
:precision="0"
:value-on-clear="5"
/>
</el-form-item>
<span class="shrink-0">次,锁定账号</span>
<el-form-item prop="authentication_value.lock_time" class="mb-0!">
<el-input-number
v-model="form.authentication_value.lock_time"
class="w-32!"
:min="1"
:max="1440"
:precision="0"
:value-on-clear="10"
/>
</el-form-item>
<span class="shrink-0">分钟</span>
</div>
</div>
</el-form-item>
</template>
<el-form-item label="嵌入白名单">
<div class="w-full space-y-2">
<!-- 设置嵌入白名单 -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useStore } from '@/stores/admin'
import { ref } from 'vue'
import AccessRestrictionDrawer from './AccessRestrictionDrawer.vue'
import XpackAccessRestrictionDrawer from './XpackAccessRestrictionDrawer.vue'

defineOptions({ name: 'ButtonAccessRestriction' })

const { auth } = useStore()
const accessRestrictionDrawer = computed(() => (auth.isCE ? AccessRestrictionDrawer : XpackAccessRestrictionDrawer))
const drawerVisible = ref(false)

function handleOpenAccessRestriction() {
Expand All @@ -21,5 +17,5 @@ function handleOpenAccessRestriction() {
<MkIcon name="icon-lock" />
<span>访问限制</span>
</el-button>
<component v-if="drawerVisible" :is="accessRestrictionDrawer" @closed="drawerVisible = false" />
<AccessRestrictionDrawer v-if="drawerVisible" @closed="drawerVisible = false" />
</template>
Loading
Loading