diff --git a/mateclaw-server/src/main/java/vip/mate/auth/service/AuthService.java b/mateclaw-server/src/main/java/vip/mate/auth/service/AuthService.java index 25f9642c..465d8e9c 100644 --- a/mateclaw-server/src/main/java/vip/mate/auth/service/AuthService.java +++ b/mateclaw-server/src/main/java/vip/mate/auth/service/AuthService.java @@ -51,7 +51,7 @@ public class AuthService { .eq(UserEntity::getEnabled, true)); if (user == null || !passwordEncoder.matches(request.getPassword(), user.getPassword())) { - throw new MateClawException("err.auth.invalid_credentials", "用户名或密码错误"); + throw new MateClawException("err.auth.invalid_credentials", 401, "用户名或密码错误"); } String token = generateToken(user); diff --git a/mateclaw-server/src/main/java/vip/mate/workspace/core/service/WorkspaceService.java b/mateclaw-server/src/main/java/vip/mate/workspace/core/service/WorkspaceService.java index 8ec886a9..1e1e493f 100644 --- a/mateclaw-server/src/main/java/vip/mate/workspace/core/service/WorkspaceService.java +++ b/mateclaw-server/src/main/java/vip/mate/workspace/core/service/WorkspaceService.java @@ -209,7 +209,7 @@ public class WorkspaceService { */ public void requirePermission(Long workspaceId, Long userId, String minRole) { if (!hasPermission(workspaceId, userId, minRole)) { - throw new MateClawException("err.workspace.insufficient_permission", "权限不足:需要 " + minRole + " 或更高角色"); + throw new MateClawException("err.workspace.insufficient_permission", 403, "权限不足:需要 " + minRole + " 或更高角色"); } } diff --git a/mateclaw-ui/src/api/index.ts b/mateclaw-ui/src/api/index.ts index 2f532171..25e52dd1 100644 --- a/mateclaw-ui/src/api/index.ts +++ b/mateclaw-ui/src/api/index.ts @@ -30,7 +30,9 @@ http.interceptors.response.use( // 后端统一响应格式 R: { code: number, msg: string, data: T } if (data && typeof data === 'object' && 'code' in data) { if (data.code === 200) return data - if (data.code === 401 || data.code === 403) { + // 401 = authentication failure → log out + // 403 = authorization failure (e.g. workspace permission denied) → keep session, surface error to caller + if (data.code === 401) { handleAuthFailure() return Promise.reject(new Error(data.msg || 'Unauthorized')) } @@ -39,7 +41,7 @@ http.interceptors.response.use( return data }, (err) => { - if (err.response?.status === 401 || err.response?.status === 403) { + if (err.response?.status === 401) { handleAuthFailure() } return Promise.reject(err.response?.data?.msg || err.message) diff --git a/mateclaw-ui/src/composables/chat/useStream.ts b/mateclaw-ui/src/composables/chat/useStream.ts index b356f5f0..926c818a 100644 --- a/mateclaw-ui/src/composables/chat/useStream.ts +++ b/mateclaw-ui/src/composables/chat/useStream.ts @@ -240,8 +240,9 @@ export function useStream(options: UseStreamOptions): UseStreamReturn { errorInfo.requestId = response.headers.get('X-Request-Id') || errorBody?.requestId || errorInfo.requestId - // 401/403 时清除 token 并跳转登录页(与 http.ts 保持一致) - if (response.status === 401 || response.status === 403) { + // 401 = authentication failure → log out (consistent with http.ts). + // 403 = authorization failure (e.g. workspace permission denied) → keep session. + if (response.status === 401) { handleAuthFailure() } throw Object.assign(new Error(errorMsg), { errorInfo }) diff --git a/mateclaw-ui/src/i18n/locales/en-US.ts b/mateclaw-ui/src/i18n/locales/en-US.ts index 0e6c9b1b..86ed0582 100644 --- a/mateclaw-ui/src/i18n/locales/en-US.ts +++ b/mateclaw-ui/src/i18n/locales/en-US.ts @@ -1561,8 +1561,8 @@ export default { allowFromPlaceholder: 'Comma-separated user IDs (empty = allow all)', denyMessage: 'Deny Message', denyMessagePlaceholder: 'Sorry, you do not have permission', - requireMention: 'Require @mention', - requireMentionTooltip: 'Whether the bot requires @mention in group chats', + requireMention: "Require {'@'}mention", + requireMentionTooltip: "Whether the bot requires {'@'}mention in group chats", }, messageFilter: { title: 'Message Filter', @@ -1639,7 +1639,7 @@ export default { qq: { step1: 'Go to QQ Open Platform and create a bot application', step2: 'Get AppID and AppSecret from the app management page, fill in below', - step3: 'Enable required message types in "Feature Config → Message Subscription" (C2C, Group @, Channel messages, etc.)', + step3: "Enable required message types in \"Feature Config → Message Subscription\" (C2C, Group {'@'}, Channel messages, etc.)", step4: 'After starting the channel, auto-receives messages via WebSocket long connection, no public IP or callback URL required', }, }, diff --git a/mateclaw-ui/src/i18n/locales/zh-CN.ts b/mateclaw-ui/src/i18n/locales/zh-CN.ts index 34d1f639..3faf0d5f 100644 --- a/mateclaw-ui/src/i18n/locales/zh-CN.ts +++ b/mateclaw-ui/src/i18n/locales/zh-CN.ts @@ -1571,8 +1571,8 @@ export default { allowFromPlaceholder: '逗号分隔用户 ID(留空 = 全部允许)', denyMessage: '拒绝提示', denyMessagePlaceholder: '抱歉,您没有使用权限', - requireMention: '需要 @提及', - requireMentionTooltip: '群聊中是否需要 @机器人才响应', + requireMention: "需要 {'@'}提及", + requireMentionTooltip: "群聊中是否需要 {'@'}机器人才响应", }, messageFilter: { title: '消息过滤', @@ -1649,7 +1649,7 @@ export default { qq: { step1: '前往 QQ 开放平台 创建机器人应用', step2: '在应用管理页面获取 AppIDAppSecret,填入下方配置', - step3: '在「功能配置 → 消息订阅」中开启需要的消息类型(C2C 消息、群聊 @消息、频道消息等)', + step3: "在「功能配置 → 消息订阅」中开启需要的消息类型(C2C 消息、群聊 {'@'}消息、频道消息等)", step4: '启动渠道后通过 WebSocket 长连接自动接收消息,无需公网 IP 和回调 URL', }, },