增加用户权限检查,实现根据用户角色所有pagetype权限控制数据访问
This commit is contained in:
parent
bb379e6c6c
commit
cb39b45b62
@ -15,23 +15,29 @@ import '../assets/styles/main.css'
|
|||||||
// Font Awesome: 全局引入图标字体样式
|
// Font Awesome: 全局引入图标字体样式
|
||||||
import '@fortawesome/fontawesome-free/css/all.min.css'
|
import '@fortawesome/fontawesome-free/css/all.min.css'
|
||||||
|
|
||||||
const app = createApp(App)
|
|
||||||
|
|
||||||
app.use(createPinia())
|
|
||||||
// 初始化认证状态(需要在pinia初始化之后)
|
|
||||||
import { useAuthStore } from '../shared/stores/auth'
|
import { useAuthStore } from '../shared/stores/auth'
|
||||||
const authStore = useAuthStore()
|
|
||||||
authStore.initAuth()
|
|
||||||
|
|
||||||
// 在路由使用前注册工具路由,避免路由匹配时的警告
|
|
||||||
import { useToolsStore } from '../shared/stores/tools'
|
import { useToolsStore } from '../shared/stores/tools'
|
||||||
const toolsStore = useToolsStore()
|
import { usePermissionStore } from '../shared/stores/permissions'
|
||||||
toolsStore.initToolRoutes(router)
|
import '../shared/utils/fetchInterceptor'
|
||||||
|
|
||||||
|
const app = createApp(App)
|
||||||
|
const pinia = createPinia()
|
||||||
|
|
||||||
|
app.use(pinia)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(naive)
|
app.use(naive)
|
||||||
|
|
||||||
// 初始化fetch拦截器(需要在pinia初始化之后)
|
async function bootstrap() {
|
||||||
import '../shared/utils/fetchInterceptor'
|
const authStore = useAuthStore()
|
||||||
|
await authStore.initAuth()
|
||||||
|
|
||||||
app.mount('#app')
|
const toolsStore = useToolsStore()
|
||||||
|
toolsStore.initToolRoutes(router)
|
||||||
|
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
await permissionStore.loadPermissions().catch(() => {})
|
||||||
|
|
||||||
|
app.mount('#app')
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap()
|
||||||
|
|||||||
@ -288,11 +288,13 @@ import { downloadImageToLocal } from '@/shared/api/common'
|
|||||||
import { usePageTypeSlug } from '@/shared/utils/slug'
|
import { usePageTypeSlug } from '@/shared/utils/slug'
|
||||||
import { resolvePagetypeToolbarOverride } from '@/core/registry/pagetypeOverride'
|
import { resolvePagetypeToolbarOverride } from '@/core/registry/pagetypeOverride'
|
||||||
import DefaultToolbar from '@/core/pagetype/default_toolbar.vue'
|
import DefaultToolbar from '@/core/pagetype/default_toolbar.vue'
|
||||||
|
import { usePermissionStore } from '@/shared/stores/permissions'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
// 使用组合式函数处理URL slug
|
// 使用组合式函数处理URL slug
|
||||||
const { pagetypeSlug, entity } = usePageTypeSlug(route)
|
const { pagetypeSlug, entity } = usePageTypeSlug(route)
|
||||||
@ -304,6 +306,7 @@ const isNew = computed(() => {
|
|||||||
return idValue === 'new' || idValue.startsWith('new-')
|
return idValue === 'new' || idValue.startsWith('new-')
|
||||||
})
|
})
|
||||||
const canEdit = ref(false)
|
const canEdit = ref(false)
|
||||||
|
const canRead = computed(() => permissionStore.canRead(entity.value))
|
||||||
|
|
||||||
const record = ref<any>({})
|
const record = ref<any>({})
|
||||||
const originalRecord = ref<any>({})
|
const originalRecord = ref<any>({})
|
||||||
@ -826,9 +829,10 @@ async function loadMeta() {
|
|||||||
|
|
||||||
metaFields.value = data?.fields || []
|
metaFields.value = data?.fields || []
|
||||||
pageMeta.value = data || {}
|
pageMeta.value = data || {}
|
||||||
|
|
||||||
|
// 权限:默认读取后端权限,决定是否可编辑
|
||||||
canEdit.value = true // 默认支持编辑
|
const pagetypeName = entity.value
|
||||||
|
canEdit.value = permissionStore.canWrite(pagetypeName)
|
||||||
|
|
||||||
// 设置默认活动标签:显示第一个标签页
|
// 设置默认活动标签:显示第一个标签页
|
||||||
if (tabs.value.length > 0) {
|
if (tabs.value.length > 0) {
|
||||||
|
|||||||
@ -24,7 +24,8 @@
|
|||||||
createRecordHandler,
|
createRecordHandler,
|
||||||
handleDeleteSelected,
|
handleDeleteSelected,
|
||||||
router,
|
router,
|
||||||
t
|
t,
|
||||||
|
canEdit: canEditList,
|
||||||
}"
|
}"
|
||||||
:entity="entity"
|
:entity="entity"
|
||||||
:search-query="searchQuery"
|
:search-query="searchQuery"
|
||||||
@ -44,6 +45,7 @@
|
|||||||
:view-mode="viewMode"
|
:view-mode="viewMode"
|
||||||
:selected-keys="selectedKeys"
|
:selected-keys="selectedKeys"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
|
:can-edit="canEditList"
|
||||||
@update:search-query="searchQuery = $event"
|
@update:search-query="searchQuery = $event"
|
||||||
@update:view-mode="viewMode = $event"
|
@update:view-mode="viewMode = $event"
|
||||||
@reload="reload"
|
@reload="reload"
|
||||||
@ -424,15 +426,18 @@ import {
|
|||||||
resolvePagetypeListActionsOverride
|
resolvePagetypeListActionsOverride
|
||||||
} from '@/core/registry/pagetypeOverride'
|
} from '@/core/registry/pagetypeOverride'
|
||||||
import { downloadImageToLocal } from '@/shared/api/common'
|
import { downloadImageToLocal } from '@/shared/api/common'
|
||||||
|
import { usePermissionStore } from '@/shared/stores/permissions'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
// 使用组合式函数处理URL slug
|
// 使用组合式函数处理URL slug
|
||||||
const { pagetypeSlug, entity } = usePageTypeSlug(route)
|
const { pagetypeSlug, entity } = usePageTypeSlug(route)
|
||||||
const title = computed(() => entity.value)
|
const title = computed(() => entity.value)
|
||||||
|
const canEditList = computed(() => permissionStore.canWrite(entity.value))
|
||||||
|
|
||||||
// 覆盖组件引用(子组件覆盖,整体覆盖由 ListPage.vue 处理)
|
// 覆盖组件引用(子组件覆盖,整体覆盖由 ListPage.vue 处理)
|
||||||
const toolbarComponent = shallowRef<any | null>(null)
|
const toolbarComponent = shallowRef<any | null>(null)
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
<i :class="loading ? 'fa fa-spinner fa-spin' : 'fa fa-refresh'"></i>
|
<i :class="loading ? 'fa fa-spinner fa-spin' : 'fa fa-refresh'"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="selectedKeys.length === 0"
|
v-if="selectedKeys.length === 0 && canEditModel"
|
||||||
class="create-btn"
|
class="create-btn"
|
||||||
@click="createRecordHandler"
|
@click="createRecordHandler"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
@ -39,7 +39,7 @@
|
|||||||
{{ t('Create') }}
|
{{ t('Create') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else-if="canEditModel"
|
||||||
class="delete-btn"
|
class="delete-btn"
|
||||||
@click="handleDeleteSelected"
|
@click="handleDeleteSelected"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
@ -61,6 +61,7 @@ interface Props {
|
|||||||
viewMode: 'card' | 'list'
|
viewMode: 'card' | 'list'
|
||||||
selectedKeys: string[]
|
selectedKeys: string[]
|
||||||
loading: boolean
|
loading: boolean
|
||||||
|
canEdit?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
@ -74,6 +75,8 @@ interface Emits {
|
|||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
const emit = defineEmits<Emits>()
|
const emit = defineEmits<Emits>()
|
||||||
|
|
||||||
|
const canEditModel = computed(() => props.canEdit !== false)
|
||||||
|
|
||||||
// 使用 computed 来处理双向绑定
|
// 使用 computed 来处理双向绑定
|
||||||
const searchQueryModel = computed({
|
const searchQueryModel = computed({
|
||||||
get: () => props.searchQuery,
|
get: () => props.searchQuery,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { loginApi, getUserInfoApi, logoutApi, isCookieExpired } from '../api/auth'
|
import { loginApi, getUserInfoApi, logoutApi, isCookieExpired } from '../api/auth'
|
||||||
|
import { usePermissionStore } from './permissions'
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
id: string
|
id: string
|
||||||
@ -25,6 +26,10 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
const response = await loginApi(username, password)
|
const response = await loginApi(username, password)
|
||||||
|
|
||||||
if (response.user) {
|
if (response.user) {
|
||||||
|
// 清除旧的权限数据
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
permissionStore.clearPermissions()
|
||||||
|
|
||||||
user.value = response.user
|
user.value = response.user
|
||||||
isAuthenticated.value = true
|
isAuthenticated.value = true
|
||||||
|
|
||||||
@ -32,6 +37,9 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
localStorage.setItem('jingrow_user', JSON.stringify(response.user))
|
localStorage.setItem('jingrow_user', JSON.stringify(response.user))
|
||||||
localStorage.setItem('jingrow_authenticated', 'true')
|
localStorage.setItem('jingrow_authenticated', 'true')
|
||||||
|
|
||||||
|
// 加载新用户的权限
|
||||||
|
await permissionStore.loadPermissions(true)
|
||||||
|
|
||||||
return { success: true, user: response.user }
|
return { success: true, user: response.user }
|
||||||
} else {
|
} else {
|
||||||
return { success: false, error: response.message || '登录失败' }
|
return { success: false, error: response.message || '登录失败' }
|
||||||
@ -55,6 +63,10 @@ export const useAuthStore = defineStore('auth', () => {
|
|||||||
isAuthenticated.value = false
|
isAuthenticated.value = false
|
||||||
localStorage.removeItem('jingrow_user')
|
localStorage.removeItem('jingrow_user')
|
||||||
localStorage.removeItem('jingrow_authenticated')
|
localStorage.removeItem('jingrow_authenticated')
|
||||||
|
|
||||||
|
// 清除权限数据
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
permissionStore.clearPermissions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useAuthStore } from './auth'
|
import { useAuthStore } from './auth'
|
||||||
|
import { usePermissionStore } from './permissions'
|
||||||
|
import { slugToPageType } from '../utils/slug'
|
||||||
|
|
||||||
export interface AppMenuItem {
|
export interface AppMenuItem {
|
||||||
id: string
|
id: string
|
||||||
@ -173,27 +175,23 @@ export const useMenuStore = defineStore('menu', () => {
|
|||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
const userType = authStore.user?.user_type
|
const userType = authStore.user?.user_type
|
||||||
|
|
||||||
// 非 System User 用户类型不显示 pagetype 和 workspace 类型的菜单项
|
|
||||||
const isSystemUser = userType === 'System User'
|
const isSystemUser = userType === 'System User'
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
return items.value.filter(m => {
|
return items.value.filter(m => {
|
||||||
// 过滤隐藏的菜单项
|
|
||||||
if (m.hidden) return false
|
if (m.hidden) return false
|
||||||
|
|
||||||
// 非 System User 的过滤逻辑
|
// 基本规则:非 System User 的菜单限制(现有逻辑)
|
||||||
if (!isSystemUser) {
|
if (!isSystemUser) {
|
||||||
// 过滤掉 pagetype 和 workspace 类型
|
|
||||||
if (m.type === 'pagetype' || m.type === 'workspace') {
|
if (m.type === 'pagetype' || m.type === 'workspace') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只允许显示的根菜单:工具、开发
|
|
||||||
const allowedRootMenus = ['tools', 'dev-group']
|
const allowedRootMenus = ['tools', 'dev-group']
|
||||||
if (!m.parentId && !allowedRootMenus.includes(m.id)) {
|
if (!m.parentId && !allowedRootMenus.includes(m.id)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开发分组下只允许显示:工具市场(非 System User 不显示应用市场、节点市场、智能体市场)
|
|
||||||
if (m.parentId === 'dev-group') {
|
if (m.parentId === 'dev-group') {
|
||||||
const allowedDevMenus = ['tool-marketplace']
|
const allowedDevMenus = ['tool-marketplace']
|
||||||
if (!allowedDevMenus.includes(m.id)) {
|
if (!allowedDevMenus.includes(m.id)) {
|
||||||
@ -201,7 +199,16 @@ export const useMenuStore = defineStore('menu', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 权限驱动规则:pagetype 类型的菜单仅在有 read 权限时显示
|
||||||
|
if (m.type === 'pagetype' && m.pagetype) {
|
||||||
|
const pagetypeName = m.pagetype
|
||||||
|
if (!permissionStore.canRead(pagetypeName)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// workspace 类型暂时不做细粒度 pagetype 检查,由 WorkspacePage 内部再过滤链接
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
100
apps/jingrow/frontend/src/shared/stores/permissions.ts
Normal file
100
apps/jingrow/frontend/src/shared/stores/permissions.ts
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export interface PagetypePermissions {
|
||||||
|
[permissionType: string]: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserPermissionsResponse {
|
||||||
|
success: boolean
|
||||||
|
user: string
|
||||||
|
roles: string[]
|
||||||
|
permissions: Record<string, PagetypePermissions>
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const usePermissionStore = defineStore('permissions', () => {
|
||||||
|
const loading = ref(false)
|
||||||
|
const loaded = ref(false)
|
||||||
|
const user = ref<string | null>(null)
|
||||||
|
const roles = ref<string[]>([])
|
||||||
|
const permissions = ref<Record<string, PagetypePermissions>>({})
|
||||||
|
|
||||||
|
async function loadPermissions(force = false) {
|
||||||
|
if (loading.value) return
|
||||||
|
if (loaded.value && !force) return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const response = await axios.get<UserPermissionsResponse>('/jingrow/user-permissions')
|
||||||
|
const data = response.data
|
||||||
|
|
||||||
|
if (!data || data.success === false) {
|
||||||
|
// 非致命错误:保持为空权限,前端仍然依赖后端校验
|
||||||
|
console.warn('Failed to load user permissions', data?.error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.value = data.user
|
||||||
|
roles.value = data.roles || []
|
||||||
|
permissions.value = data.permissions || {}
|
||||||
|
loaded.value = true
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Error loading user permissions', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasPermission(pagetype: string, permissionType: string): boolean {
|
||||||
|
if (!pagetype || !permissionType) return false
|
||||||
|
const perms = permissions.value[pagetype]
|
||||||
|
if (!perms) return false
|
||||||
|
return Boolean(perms[permissionType])
|
||||||
|
}
|
||||||
|
|
||||||
|
function canRead(pagetype: string): boolean {
|
||||||
|
return hasPermission(pagetype, 'read') || hasPermission(pagetype, 'select')
|
||||||
|
}
|
||||||
|
|
||||||
|
function canWrite(pagetype: string): boolean {
|
||||||
|
// 视为“可编辑”:拥有 write 或 create 或 delete 等任一权限
|
||||||
|
return (
|
||||||
|
hasPermission(pagetype, 'write') ||
|
||||||
|
hasPermission(pagetype, 'create') ||
|
||||||
|
hasPermission(pagetype, 'delete') ||
|
||||||
|
hasPermission(pagetype, 'submit') ||
|
||||||
|
hasPermission(pagetype, 'cancel') ||
|
||||||
|
hasPermission(pagetype, 'amend')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露一个便捷的只读权限 map,用于调试或全局判断
|
||||||
|
const readablePagetypes = computed(() =>
|
||||||
|
Object.keys(permissions.value).filter((pt) => canRead(pt))
|
||||||
|
)
|
||||||
|
|
||||||
|
// 清除权限数据(用户登出时调用)
|
||||||
|
function clearPermissions() {
|
||||||
|
loading.value = false
|
||||||
|
loaded.value = false
|
||||||
|
user.value = null
|
||||||
|
roles.value = []
|
||||||
|
permissions.value = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
loaded,
|
||||||
|
user,
|
||||||
|
roles,
|
||||||
|
permissions,
|
||||||
|
loadPermissions,
|
||||||
|
hasPermission,
|
||||||
|
canRead,
|
||||||
|
canWrite,
|
||||||
|
readablePagetypes,
|
||||||
|
clearPermissions,
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -49,10 +49,12 @@ import { Icon } from '@iconify/vue'
|
|||||||
import { t } from '@/shared/i18n'
|
import { t } from '@/shared/i18n'
|
||||||
import { getWorkspace } from '@/shared/api/common'
|
import { getWorkspace } from '@/shared/api/common'
|
||||||
import { pageTypeToSlug } from '@/shared/utils/slug'
|
import { pageTypeToSlug } from '@/shared/utils/slug'
|
||||||
|
import { usePermissionStore } from '@/shared/stores/permissions'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
const name = computed(() => String(route.params.name || 'Build'))
|
const name = computed(() => String(route.params.name || 'Build'))
|
||||||
const decodedName = computed(() => decodeURIComponent(name.value))
|
const decodedName = computed(() => decodeURIComponent(name.value))
|
||||||
@ -95,8 +97,11 @@ async function load() {
|
|||||||
for (const block of layout || []) {
|
for (const block of layout || []) {
|
||||||
if (block.type === 'card') {
|
if (block.type === 'card') {
|
||||||
const title = block.data?.card_name || 'Section'
|
const title = block.data?.card_name || 'Section'
|
||||||
const col = Number(block.data?.col || 6) // 按 12 栅格,6=两列,3=四列
|
const col = Number(block.data?.col || 6)
|
||||||
resultItems.push({ key: `card-${title}-${col}-${resultItems.length}` , type:'card', title, col, links: grouped[title] || [], classes: mapColToClasses(col) })
|
const cardLinks = grouped[title] || []
|
||||||
|
// 如果卡片下所有链接都被权限过滤掉,则跳过该卡片
|
||||||
|
if (!cardLinks.length) continue
|
||||||
|
resultItems.push({ key: `card-${title}-${col}-${resultItems.length}` , type:'card', title, col, links: cardLinks, classes: mapColToClasses(col) })
|
||||||
} else if (block.type === 'shortcut') {
|
} else if (block.type === 'shortcut') {
|
||||||
// 处理快捷方式
|
// 处理快捷方式
|
||||||
const title = block.data?.shortcut_name || 'Shortcut'
|
const title = block.data?.shortcut_name || 'Shortcut'
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import logging
|
|||||||
|
|
||||||
from jingrow.utils.auth import login, logout, get_user_info, set_context, get_jingrow_cloud_url, get_jingrow_cloud_api_headers
|
from jingrow.utils.auth import login, logout, get_user_info, set_context, get_jingrow_cloud_url, get_jingrow_cloud_api_headers
|
||||||
from jingrow.config import Config
|
from jingrow.config import Config
|
||||||
|
from jingrow.utils.jingrow_api import get_user_pagetype_permissions_from_jingrow
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
@ -41,6 +42,14 @@ class UserInfoResponse(BaseModel):
|
|||||||
user_info: Optional[dict] = None
|
user_info: Optional[dict] = None
|
||||||
message: Optional[str] = None
|
message: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class UserPermissionsResponse(BaseModel):
|
||||||
|
success: bool
|
||||||
|
user: Optional[str] = None
|
||||||
|
roles: Optional[list[str]] = None
|
||||||
|
permissions: Optional[dict] = None
|
||||||
|
error: Optional[str] = None
|
||||||
|
|
||||||
COOKIE_CONFIG = {
|
COOKIE_CONFIG = {
|
||||||
"httponly": True,
|
"httponly": True,
|
||||||
"samesite": "lax",
|
"samesite": "lax",
|
||||||
@ -213,3 +222,22 @@ async def get_user_info_route(session_cookie: Optional[str] = Depends(get_sessio
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取用户信息异常: {str(e)}", exc_info=True)
|
logger.error(f"获取用户信息异常: {str(e)}", exc_info=True)
|
||||||
raise HTTPException(status_code=500, detail=f"获取用户信息异常: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"获取用户信息异常: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/jingrow/user-permissions", response_model=UserPermissionsResponse)
|
||||||
|
async def get_user_permissions_route(session_cookie: Optional[str] = Depends(get_session_cookie)):
|
||||||
|
"""获取当前登录用户的 PageType 权限"""
|
||||||
|
if not session_cookie:
|
||||||
|
raise HTTPException(status_code=401, detail="未提供认证信息")
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = get_user_pagetype_permissions_from_jingrow(session_cookie)
|
||||||
|
if not result or not result.get("success"):
|
||||||
|
error_msg = result.get("error") if isinstance(result, dict) else "获取权限失败"
|
||||||
|
raise HTTPException(status_code=400, detail=error_msg)
|
||||||
|
return result
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取用户权限异常: {str(e)}", exc_info=True)
|
||||||
|
raise HTTPException(status_code=500, detail=f"获取用户权限异常: {str(e)}")
|
||||||
|
|||||||
@ -225,6 +225,34 @@ def get_ai_settings_from_jingrow():
|
|||||||
log_error(f"获取AI Settings配置异常: {str(e)}")
|
log_error(f"获取AI Settings配置异常: {str(e)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_pagetype_permissions_from_jingrow(session_cookie: str | None):
|
||||||
|
"""从 Jingrow 获取当前登录用户在所有 PageType 上的权限信息"""
|
||||||
|
if not session_cookie:
|
||||||
|
return {"success": False, "error": "Session cookie 缺失"}
|
||||||
|
|
||||||
|
api_url = f"{Config.jingrow_server_url}/api/action/jingrow.ai.utils.jlocal.get_user_pagetype_permissions"
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Cookie": f"sid={session_cookie}",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = requests.post(api_url, headers=headers, json={}, timeout=10)
|
||||||
|
if resp.status_code != 200:
|
||||||
|
log_error(f"获取用户权限失败: HTTP {resp.status_code} {resp.text}")
|
||||||
|
return {"success": False, "error": f"HTTP {resp.status_code}"}
|
||||||
|
|
||||||
|
result = resp.json()
|
||||||
|
if isinstance(result, dict) and "message" in result:
|
||||||
|
result = result["message"]
|
||||||
|
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"获取用户权限异常: {str(e)}")
|
||||||
|
return {"success": False, "error": str(e)}
|
||||||
|
|
||||||
def get_agent_detail(name: str, session_cookie: str = None):
|
def get_agent_detail(name: str, session_cookie: str = None):
|
||||||
"""
|
"""
|
||||||
获取智能体详情
|
获取智能体详情
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user