fix(security): 角色资源树回显防权限放大 + 401 刷新防死循环
- assign-resources-form:只保存叶子键 getCheckedKeys(true),回显 setCheckedKeys(leafOnly) - http.ts:_retry 标记只重放一次 + 排除 login/refresh Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
23e228783c
commit
7ae220581a
@ -65,9 +65,12 @@ export class HttpClient {
|
||||
return Promise.reject(new ApiError(body.code, body.message))
|
||||
},
|
||||
async (error: AxiosError) => {
|
||||
const config = error.config
|
||||
// 401 自动刷新并重放一次
|
||||
if (error.response?.status === 401 && config) {
|
||||
const config = error.config as (AxiosRequestConfig & { _retry?: boolean }) | undefined
|
||||
const url = config?.url ?? ''
|
||||
const isAuthEndpoint = url.includes('/auth/login') || url.includes('/auth/refresh')
|
||||
// 401 自动刷新并重放一次(登录/刷新接口自身 401 不重放,_retry 防死循环)
|
||||
if (error.response?.status === 401 && config && !config._retry && !isAuthEndpoint) {
|
||||
config._retry = true
|
||||
try {
|
||||
const token = await this.refresh()
|
||||
config.headers = config.headers ?? {}
|
||||
|
||||
@ -7,13 +7,12 @@
|
||||
node-key="code"
|
||||
show-checkbox
|
||||
:props="{ label: 'name', children: 'children' }"
|
||||
:default-checked-keys="assigned ?? []"
|
||||
default-expand-all
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import { useRequest } from '@/composables/useRequest'
|
||||
import { listResources } from '@/api/resource'
|
||||
import { listAssignedResources } from '@/api/role'
|
||||
@ -25,8 +24,8 @@ defineOptions({ name: 'AssignResourcesForm' })
|
||||
const props = defineProps<{ roleCode: string }>()
|
||||
|
||||
interface TreeApi {
|
||||
getCheckedKeys: () => (string | number)[]
|
||||
getHalfCheckedKeys: () => (string | number)[]
|
||||
getCheckedKeys: (leafOnly?: boolean) => (string | number)[]
|
||||
setCheckedKeys: (keys: (string | number)[], leafOnly?: boolean) => void
|
||||
}
|
||||
const treeRef = ref<TreeApi>()
|
||||
|
||||
@ -36,10 +35,18 @@ const { data: assigned } = useRequest((signal: AbortSignal) => listAssignedResou
|
||||
const tree = computed(() => buildTree(resourceList.value ?? []) as TreeNode<Resource>[])
|
||||
const ready = computed(() => resourceList.value !== undefined && assigned.value !== undefined)
|
||||
|
||||
// 回显:仅叶子节点勾选,父节点由叶子自动推导,避免 default-checked-keys 级联全选
|
||||
watch(ready, async (r) => {
|
||||
if (r) {
|
||||
await nextTick()
|
||||
treeRef.value?.setCheckedKeys(assigned.value ?? [], true)
|
||||
}
|
||||
})
|
||||
|
||||
function submit(): { resourceCodes: string[] } {
|
||||
const checked = treeRef.value?.getCheckedKeys() ?? []
|
||||
const half = treeRef.value?.getHalfCheckedKeys() ?? []
|
||||
return { resourceCodes: [...new Set([...checked, ...half].map(String))] }
|
||||
// 只保存叶子节点:半选父节点由叶子推导,避免回显级联造成权限放大
|
||||
const checked = treeRef.value?.getCheckedKeys(true) ?? []
|
||||
return { resourceCodes: [...new Set(checked.map(String))] }
|
||||
}
|
||||
|
||||
defineExpose({ submit })
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -68,15 +68,13 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
|
||||
rules: [
|
||||
...['primary', 'success', 'warning', 'danger', 'info'].flatMap((color) => [
|
||||
rules: ['primary', 'success', 'warning', 'danger', 'info'].flatMap((color) => [
|
||||
[`bg-${color}-light-3`, { 'background-color': `var(--wm-color-${color}-light-3)` }],
|
||||
[`bg-${color}-light-5`, { 'background-color': `var(--wm-color-${color}-light-5)` }],
|
||||
[`bg-${color}-light-7`, { 'background-color': `var(--wm-color-${color}-light-7)` }],
|
||||
[`bg-${color}-light-9`, { 'background-color': `var(--wm-color-${color}-light-9)` }],
|
||||
[`text-${color}-dark-2`, { color: `var(--wm-color-${color}-dark-2)` }],
|
||||
]),
|
||||
],
|
||||
|
||||
shortcuts: {
|
||||
// 布局
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user