From b8ba0ea6a0bb589b123677ec216a8724b6ca0a91 Mon Sep 17 00:00:00 2001 From: "DESKTOP-72TV0V4\\caoxiaozhu" Date: Thu, 7 May 2026 14:34:42 +0800 Subject: [PATCH] feat: add auth module with login and access control --- document/work-log/2026-05-07.md | 15 ++- server/src/app/api/v1/endpoints/auth.py | 21 ++++ server/src/app/api/v1/router.py | 2 + server/src/app/core/admin_secret.py | 53 +++++++++ server/src/app/schemas/auth.py | 24 ++++ server/src/app/services/auth.py | 144 ++++++++++++++++++++++++ server/src/app/services/employee.py | 5 + server/tests/test_auth_service.py | 72 ++++++++++++ web/UI/设置界面.png | Bin 0 -> 104724 bytes web/src/composables/useSystemState.js | 110 +++++++++++++----- web/src/router/index.js | 7 +- web/src/services/auth.js | 8 ++ web/src/utils/accessControl.js | 62 ++++++++++ web/src/views/AppShellRouteView.vue | 6 +- web/src/views/LoginView.vue | 6 +- 15 files changed, 501 insertions(+), 34 deletions(-) create mode 100644 server/src/app/api/v1/endpoints/auth.py create mode 100644 server/src/app/core/admin_secret.py create mode 100644 server/src/app/schemas/auth.py create mode 100644 server/src/app/services/auth.py create mode 100644 server/tests/test_auth_service.py create mode 100644 web/UI/设置界面.png create mode 100644 web/src/services/auth.js create mode 100644 web/src/utils/accessControl.js diff --git a/document/work-log/2026-05-07.md b/document/work-log/2026-05-07.md index 4fce798..e590630 100644 --- a/document/work-log/2026-05-07.md +++ b/document/work-log/2026-05-07.md @@ -6,4 +6,17 @@ - feat: add employee management, backend health check, and UI improvements - 完成了员工管理模块(后端 + 前端) - 添加了后端健康检查 - - 整理了 UI 资源 \ No newline at end of file + - 整理了 UI 资源 + +- **提交 2d56bc2** (13:48) + - feat: enhance employee CRUD with search, filters, and security module + - 增强了员工搜索和筛选功能 + - 添加了安全模块(security.py) + - 添加了单元测试 + +--- + +# 待处理 + +- [ ] 安装 PostgreSQL +- [ ] 创建 x_financial 数据库 \ No newline at end of file diff --git a/server/src/app/api/v1/endpoints/auth.py b/server/src/app/api/v1/endpoints/auth.py new file mode 100644 index 0000000..d3cbbe9 --- /dev/null +++ b/server/src/app/api/v1/endpoints/auth.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +from typing import Annotated + +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session + +from app.api.deps import get_db +from app.schemas.auth import LoginRequest, LoginResponse +from app.services.auth import AuthService + +router = APIRouter(prefix="/auth") +DbSession = Annotated[Session, Depends(get_db)] + + +@router.post("/login", response_model=LoginResponse) +def login(payload: LoginRequest, db: DbSession) -> LoginResponse: + try: + return AuthService(db).login(payload) + except ValueError as exc: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(exc)) from exc diff --git a/server/src/app/api/v1/router.py b/server/src/app/api/v1/router.py index e6144d5..bedee42 100644 --- a/server/src/app/api/v1/router.py +++ b/server/src/app/api/v1/router.py @@ -1,5 +1,6 @@ from fastapi import APIRouter +from app.api.v1.endpoints.auth import router as auth_router from app.api.v1.endpoints.bootstrap import router as bootstrap_router from app.api.v1.endpoints.employees import router as employees_router from app.api.v1.endpoints.health import router as health_router @@ -8,5 +9,6 @@ from app.api.v1.endpoints.reimbursements import router as reimbursements_router router = APIRouter() router.include_router(health_router, tags=["health"]) router.include_router(bootstrap_router, tags=["bootstrap"]) +router.include_router(auth_router, tags=["auth"]) router.include_router(employees_router, prefix="/employees", tags=["employees"]) router.include_router(reimbursements_router, prefix="/reimbursements", tags=["reimbursements"]) diff --git a/server/src/app/core/admin_secret.py b/server/src/app/core/admin_secret.py new file mode 100644 index 0000000..865843a --- /dev/null +++ b/server/src/app/core/admin_secret.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +import hashlib +import json +import secrets +from pathlib import Path + +from app.core.config import SERVER_DIR + +ADMIN_SECRET_FILE = SERVER_DIR / ".secrets" / "admin.json" + + +def read_admin_secret() -> dict[str, object] | None: + if not ADMIN_SECRET_FILE.exists(): + return None + + try: + payload = json.loads(ADMIN_SECRET_FILE.read_text(encoding="utf-8")) + except (OSError, json.JSONDecodeError): + return None + + if ( + payload + and payload.get("algorithm") == "scrypt" + and isinstance(payload.get("username"), str) + and isinstance(payload.get("salt"), str) + and isinstance(payload.get("derived_key"), str) + ): + return payload + + return None + + +def verify_admin_secret(password: str, record: dict[str, object]) -> bool: + try: + salt = bytes.fromhex(str(record["salt"])) + stored_key = bytes.fromhex(str(record["derived_key"])) + key_length = int(record.get("key_length", 64)) + n_value = int(record.get("N", 16384)) + r_value = int(record.get("r", 8)) + p_value = int(record.get("p", 1)) + except (KeyError, TypeError, ValueError): + return False + + derived_key = hashlib.scrypt( + password.encode("utf-8"), + salt=salt, + n=n_value, + r=r_value, + p=p_value, + dklen=key_length, + ) + return secrets.compare_digest(derived_key, stored_key) diff --git a/server/src/app/schemas/auth.py b/server/src/app/schemas/auth.py new file mode 100644 index 0000000..aa240f4 --- /dev/null +++ b/server/src/app/schemas/auth.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from pydantic import BaseModel, EmailStr, Field + + +class LoginRequest(BaseModel): + username: str = Field(min_length=1, max_length=255) + password: str = Field(min_length=1, max_length=128) + + +class AuthUserRead(BaseModel): + username: str + name: str + role: str + roleCodes: list[str] = Field(default_factory=list) + email: EmailStr | str + avatar: str + isAdmin: bool = False + + +class LoginResponse(BaseModel): + ok: bool = True + detail: str = "登录成功。" + user: AuthUserRead diff --git a/server/src/app/services/auth.py b/server/src/app/services/auth.py new file mode 100644 index 0000000..a4ffa2a --- /dev/null +++ b/server/src/app/services/auth.py @@ -0,0 +1,144 @@ +from __future__ import annotations + +from dataclasses import dataclass + +from sqlalchemy import func, select +from sqlalchemy.orm import Session, selectinload + +from app.core.admin_secret import read_admin_secret, verify_admin_secret +from app.core.config import get_settings +from app.core.logging import get_logger +from app.core.security import verify_password +from app.models.employee import Employee +from app.schemas.auth import AuthUserRead, LoginRequest, LoginResponse +from app.services.employee import EmployeeService +from app.services.employee_seed import ROLE_DISPLAY_ORDER + +logger = get_logger("app.services.auth") + +ROLE_LABELS = { + "manager": "管理员", + "finance": "财务人员", + "executive": "高级管理人员", + "approver": "审批负责人", + "auditor": "审计观察员", + "user": "使用者", +} + + +@dataclass(slots=True) +class AuthenticatedUser: + username: str + name: str + role: str + role_codes: list[str] + email: str + avatar: str + is_admin: bool = False + + +class AuthService: + def __init__(self, db: Session) -> None: + self.db = db + self.settings = get_settings() + + def login(self, payload: LoginRequest) -> LoginResponse: + identifier = payload.username.strip() + password = payload.password + + admin_user = self._authenticate_admin(identifier, password) + if admin_user is not None: + logger.info("Admin login succeeded identifier=%s", identifier) + return LoginResponse(user=self._serialize_user(admin_user)) + + employee_user = self._authenticate_employee(identifier, password) + if employee_user is not None: + logger.info("Employee login succeeded identifier=%s role_codes=%s", identifier, ",".join(employee_user.role_codes)) + return LoginResponse(user=self._serialize_user(employee_user)) + + logger.warning("Login failed identifier=%s", identifier) + raise ValueError("账号或密码错误。") + + def _authenticate_admin(self, identifier: str, password: str) -> AuthenticatedUser | None: + record = read_admin_secret() + if record is None: + return None + + admin_username = str(record.get("username", "")).strip() + admin_email = str(self.settings.admin_email or "").strip() + normalized_identifier = identifier.casefold() + + allowed_identifiers = { + value.casefold() + for value in [admin_username, admin_email] + if value + } + + if normalized_identifier not in allowed_identifiers: + return None + + if not verify_admin_secret(password, record): + return None + + display_name = admin_username or admin_email or "系统管理员" + return AuthenticatedUser( + username=admin_username or admin_email, + name=display_name, + role="管理员", + role_codes=["manager"], + email=admin_email or f"{admin_username}@local", + avatar=display_name[:1].upper(), + is_admin=True, + ) + + def _authenticate_employee(self, identifier: str, password: str) -> AuthenticatedUser | None: + if not self.settings.setup_completed: + return None + + EmployeeService(self.db).ensure_directory_ready() + + stmt = ( + select(Employee) + .options(selectinload(Employee.roles)) + .where(func.lower(Employee.email) == identifier.lower()) + ) + employee = self.db.execute(stmt).scalars().first() + + if employee is None or not employee.password_hash: + return None + + if employee.employment_status == "停用": + logger.warning("Disabled employee login blocked identifier=%s", identifier) + return None + + if not verify_password(password, employee.password_hash): + return None + + sorted_roles = sorted( + list(employee.roles), + key=lambda item: (ROLE_DISPLAY_ORDER.get(item.role_code, 999), item.name), + ) + role_codes = [role.role_code for role in sorted_roles] + primary_role_code = role_codes[0] if role_codes else "user" + + return AuthenticatedUser( + username=employee.email, + name=employee.name, + role=ROLE_LABELS.get(primary_role_code, "使用者"), + role_codes=role_codes or ["user"], + email=employee.email, + avatar=(employee.name or "?")[:1].upper(), + is_admin=False, + ) + + @staticmethod + def _serialize_user(user: AuthenticatedUser) -> AuthUserRead: + return AuthUserRead( + username=user.username, + name=user.name, + role=user.role, + roleCodes=user.role_codes, + email=user.email, + avatar=user.avatar, + isAdmin=user.is_admin, + ) diff --git a/server/src/app/services/employee.py b/server/src/app/services/employee.py index 52f9ac1..921fc96 100644 --- a/server/src/app/services/employee.py +++ b/server/src/app/services/employee.py @@ -36,6 +36,7 @@ from app.services.employee_seed import ( ) logger = get_logger("app.services.employee") +DEFAULT_EMPLOYEE_PASSWORD = "123456" STATUS_TONE_MAP = { "在职": "success", @@ -150,6 +151,7 @@ class EmployeeService: employment_status=payload.employment_status, sync_state=payload.sync_state, spotlight=payload.spotlight, + password_hash=hash_password(DEFAULT_EMPLOYEE_PASSWORD), last_sync_at=datetime.now(), ) @@ -432,6 +434,9 @@ class EmployeeService: if employee.manager_id is None and manager_employee_no: employee.manager = employees_by_no.get(manager_employee_no) + if not employee.password_hash: + employee.password_hash = hash_password(DEFAULT_EMPLOYEE_PASSWORD) + if not employee.roles: employee.roles = self._sorted_roles( [ diff --git a/server/tests/test_auth_service.py b/server/tests/test_auth_service.py new file mode 100644 index 0000000..fa06bdf --- /dev/null +++ b/server/tests/test_auth_service.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from sqlalchemy import create_engine +from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy.pool import StaticPool + +from app.db.base import Base +from app.schemas.auth import LoginRequest +from app.services.auth import AuthService +from app.services.employee import EmployeeService + + +def build_session() -> Session: + engine = create_engine( + "sqlite+pysqlite:///:memory:", + connect_args={"check_same_thread": False}, + poolclass=StaticPool, + ) + Base.metadata.create_all(bind=engine) + session_factory = sessionmaker(bind=engine, autoflush=False, autocommit=False) + return session_factory() + + +def test_employee_can_login_with_seed_default_password() -> None: + with build_session() as db: + employee = EmployeeService(db).list_employees()[0] + result = AuthService(db).login( + LoginRequest(username=employee.email, password="123456") + ) + + assert result.ok is True + assert result.user.username == employee.email + assert result.user.name == employee.name + assert result.user.roleCodes + assert result.user.isAdmin is False + + +def test_admin_can_login_with_secret(monkeypatch) -> None: + with build_session() as db: + monkeypatch.setattr( + "app.services.auth.read_admin_secret", + lambda: { + "username": "superadmin", + "algorithm": "scrypt", + "salt": "00", + "derived_key": "00", + }, + ) + monkeypatch.setattr("app.services.auth.verify_admin_secret", lambda password, record: password == "admin123") + + result = AuthService(db).login( + LoginRequest(username="superadmin", password="admin123") + ) + + assert result.ok is True + assert result.user.username == "superadmin" + assert result.user.isAdmin is True + assert result.user.roleCodes == ["manager"] + + +def test_disabled_employee_cannot_login() -> None: + with build_session() as db: + service = EmployeeService(db) + employee = service.list_employees()[0] + service.disable_employee(employee.id) + + try: + AuthService(db).login(LoginRequest(username=employee.email, password="123456")) + except ValueError as exc: + assert "账号或密码错误" in str(exc) + else: + raise AssertionError("disabled employee login should be rejected") diff --git a/web/UI/设置界面.png b/web/UI/设置界面.png new file mode 100644 index 0000000000000000000000000000000000000000..2150432913a193399c91cab236323146d959e7d5 GIT binary patch literal 104724 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 literal 0 HcmV?d00001 diff --git a/web/src/composables/useSystemState.js b/web/src/composables/useSystemState.js index 1c3b267..7ca8de7 100644 --- a/web/src/composables/useSystemState.js +++ b/web/src/composables/useSystemState.js @@ -1,18 +1,20 @@ import { computed, ref } from 'vue' import { - loginBootstrapAdmin, saveBootstrapConfig, testBootstrapDatabase, testBootstrapRuntime } from '../services/bootstrap.js' +import { login as loginByAccount } from '../services/auth.js' +import { resolveDefaultAuthorizedRoute } from '../utils/accessControl.js' import { useToast } from './useToast.js' const AUTH_STORAGE_KEY = 'x-financial-authenticated' const AUTH_USERNAME_KEY = 'x-financial-auth-username' +const AUTH_USER_KEY = 'x-financial-auth-user' const AUTH_LAST_ACTIVITY_KEY = 'x-financial-auth-last-activity' const DEFAULT_USER_NAME = '系统管理员' -const DEFAULT_USER_ROLE = '财务管理员' +const DEFAULT_USER_ROLE = '管理员' const SESSION_ACTIVITY_EVENTS = ['pointerdown', 'keydown', 'scroll', 'touchstart', 'visibilitychange'] const authIdleTimeoutMinutes = Number(import.meta.env.VITE_AUTH_IDLE_TIMEOUT_MINUTES || 30) const authIdleTimeoutMs = @@ -74,6 +76,67 @@ function readStoredUsername() { return window.sessionStorage.getItem(AUTH_USERNAME_KEY) || '' } +function buildAnonymousUser() { + return { + username: '', + name: '', + role: '', + roleCodes: [], + email: '', + avatar: '', + isAdmin: false + } +} + +function buildLegacyAdminUser(username = '') { + const normalized = String(username || '').trim() + const name = normalized || DEFAULT_USER_NAME + + return { + username: normalized, + name, + role: DEFAULT_USER_ROLE, + roleCodes: ['manager'], + email: '', + avatar: name.slice(0, 1).toUpperCase(), + isAdmin: true + } +} + +function readStoredUser() { + if (typeof window === 'undefined') { + return buildAnonymousUser() + } + + const raw = window.sessionStorage.getItem(AUTH_USER_KEY) + + if (raw) { + try { + const payload = JSON.parse(raw) + if (payload && typeof payload === 'object') { + const username = String(payload.username || '').trim() + const name = String(payload.name || username || DEFAULT_USER_NAME).trim() + const roleCodes = Array.isArray(payload.roleCodes) ? payload.roleCodes.filter(Boolean) : [] + + return { + username, + name, + role: String(payload.role || DEFAULT_USER_ROLE), + roleCodes, + email: String(payload.email || ''), + avatar: String(payload.avatar || name.slice(0, 1).toUpperCase()), + isAdmin: Boolean(payload.isAdmin) + } + } + } catch { + return buildLegacyAdminUser(readStoredUsername()) + } + } + + const legacyUsername = readStoredUsername() + return legacyUsername ? buildLegacyAdminUser(legacyUsername) : buildAnonymousUser() +} + function readLastActivityAt() { if (typeof window === 'undefined') { return 0 @@ -82,17 +145,6 @@ function readLastActivityAt() { return Number(window.sessionStorage.getItem(AUTH_LAST_ACTIVITY_KEY) || 0) } -function buildCurrentUser(username = '') { - const normalized = String(username || '').trim() - const name = normalized || DEFAULT_USER_NAME - - return { - name, - role: DEFAULT_USER_ROLE, - avatar: name.slice(0, 1).toUpperCase() - } -} - function isSessionExpired(now = Date.now()) { if (!readAuthState()) { return false @@ -107,19 +159,22 @@ function isSessionExpired(now = Date.now()) { return now - lastActivityAt > authIdleTimeoutMs } -function persistAuthState(value, username = '') { +function persistAuthState(value, user = null) { if (typeof window === 'undefined') { return } if (value) { window.sessionStorage.setItem(AUTH_STORAGE_KEY, 'true') - window.sessionStorage.setItem(AUTH_USERNAME_KEY, String(username || '').trim()) + const normalizedUser = user || buildAnonymousUser() + window.sessionStorage.setItem(AUTH_USERNAME_KEY, String(normalizedUser.username || '').trim()) + window.sessionStorage.setItem(AUTH_USER_KEY, JSON.stringify(normalizedUser)) return } window.sessionStorage.removeItem(AUTH_STORAGE_KEY) window.sessionStorage.removeItem(AUTH_USERNAME_KEY) + window.sessionStorage.removeItem(AUTH_USER_KEY) window.sessionStorage.removeItem(AUTH_LAST_ACTIVITY_KEY) } @@ -213,7 +268,7 @@ function syncAuthSession(options = {}) { if (!readAuthState()) { loggedIn.value = false - currentUser.value = buildCurrentUser('') + currentUser.value = buildAnonymousUser() clearSessionTimeout() return false } @@ -224,7 +279,7 @@ function syncAuthSession(options = {}) { } loggedIn.value = true - currentUser.value = buildCurrentUser(readStoredUsername()) + currentUser.value = readStoredUser() scheduleSessionTimeout() return true } @@ -250,7 +305,7 @@ const databaseTestMessage = ref('') const loginSubmitting = ref(false) const loginError = ref('') const loggedIn = ref(readAuthState() && !isSessionExpired()) -const currentUser = ref(buildCurrentUser(readStoredUsername())) +const currentUser = ref(readStoredUser()) if (!loggedIn.value && readAuthState()) { persistAuthState(false) @@ -288,7 +343,7 @@ function resetFromClientEnv() { applyBootstrapState(readClientBootstrapState()) clearSetupRuntimeState() loginError.value = '' - currentUser.value = buildCurrentUser(readStoredUsername()) + currentUser.value = readStoredUser() } async function handleSetupSubmit(payload) { @@ -382,19 +437,20 @@ async function handleLogin(credentials) { loginError.value = '' try { - await loginBootstrapAdmin({ + const response = await loginByAccount({ username: credentials.username, password: credentials.password }) + const user = response?.user || buildAnonymousUser() loggedIn.value = true - persistAuthState(true, credentials.username) - currentUser.value = buildCurrentUser(credentials.username) + persistAuthState(true, user) + currentUser.value = user touchAuthActivity(true) return true } catch (error) { logout('invalid', { redirect: false }) - loginError.value = error.message || '登录失败,请检查管理员账号和密码。' + loginError.value = error.message || '登录失败,请检查账号和密码。' toast(loginError.value) return false } finally { @@ -408,7 +464,7 @@ function logout(reason = 'manual', options = {}) { loggedIn.value = false persistAuthState(false) - currentUser.value = buildCurrentUser('') + currentUser.value = buildAnonymousUser() clearSessionTimeout() if (notify) { @@ -421,7 +477,7 @@ function logout(reason = 'manual', options = {}) { } function handleRecoverPassword() { - toast('请联系系统管理员重置密码。管理员密码不会写入 .env。') + toast('请联系系统管理员重置账号密码。') } function handleSsoLogin() { @@ -430,7 +486,7 @@ function handleSsoLogin() { function resolveEntryRoute() { loggedIn.value = syncAuthSession() - currentUser.value = buildCurrentUser(readStoredUsername()) + currentUser.value = readStoredUser() if (!isInitialized.value) { return { name: 'setup' } @@ -440,7 +496,7 @@ function resolveEntryRoute() { return { name: 'login' } } - return { name: 'app-overview' } + return resolveDefaultAuthorizedRoute(currentUser.value) } export function useSystemState() { diff --git a/web/src/router/index.js b/web/src/router/index.js index 794981b..5474fdf 100644 --- a/web/src/router/index.js +++ b/web/src/router/index.js @@ -3,6 +3,7 @@ import { createRouter, createWebHistory } from 'vue-router' import { checkBackendHealth } from '../composables/useBackendHealth.js' import { appViews } from '../composables/useNavigation.js' import { useSystemState } from '../composables/useSystemState.js' +import { canAccessAppView } from '../utils/accessControl.js' import AppShellRouteView from '../views/AppShellRouteView.vue' import BackendUnavailableRouteView from '../views/BackendUnavailableRouteView.vue' import LoginRouteView from '../views/LoginRouteView.vue' @@ -80,7 +81,7 @@ const router = createRouter({ }) router.beforeEach((to) => { - const { isInitialized, loggedIn, resolveEntryRoute, syncAuthSession } = useSystemState() + const { currentUser, isInitialized, loggedIn, resolveEntryRoute, syncAuthSession } = useSystemState() const authActive = syncAuthSession({ notify: Boolean(to.meta.requiresAuth) }) if (!isInitialized.value) { @@ -105,6 +106,10 @@ router.beforeEach((to) => { return resolveEntryRoute() } + if (ok && typeof to.meta.appView === 'string' && !canAccessAppView(currentUser.value, to.meta.appView)) { + return resolveEntryRoute() + } + return true }) } diff --git a/web/src/services/auth.js b/web/src/services/auth.js new file mode 100644 index 0000000..5390a57 --- /dev/null +++ b/web/src/services/auth.js @@ -0,0 +1,8 @@ +import { apiRequest } from './api.js' + +export function login(payload) { + return apiRequest('/auth/login', { + method: 'POST', + body: JSON.stringify(payload) + }) +} diff --git a/web/src/utils/accessControl.js b/web/src/utils/accessControl.js new file mode 100644 index 0000000..2350349 --- /dev/null +++ b/web/src/utils/accessControl.js @@ -0,0 +1,62 @@ +export const DEFAULT_APP_VIEW_ORDER = [ + 'overview', + 'workbench', + 'requests', + 'approval', + 'chat', + 'policies', + 'audit', + 'employees' +] + +const ALWAYS_VISIBLE_VIEWS = new Set(['workbench', 'requests', 'chat']) +const VIEW_ROLE_RULES = { + overview: ['finance', 'executive'], + approval: ['approver'], + policies: ['manager'], + audit: ['auditor'], + employees: ['manager'] +} + +function normalizedRoleCodes(user) { + if (!user) { + return [] + } + + return Array.isArray(user.roleCodes) ? user.roleCodes.filter(Boolean) : [] +} + +export function isManagerUser(user) { + return Boolean(user?.isAdmin) || normalizedRoleCodes(user).includes('manager') +} + +export function canAccessAppView(user, viewId) { + if (!viewId || !user) { + return false + } + + if (isManagerUser(user)) { + return true + } + + if (ALWAYS_VISIBLE_VIEWS.has(viewId)) { + return true + } + + const requiredRoles = VIEW_ROLE_RULES[viewId] || [] + const roleCodes = normalizedRoleCodes(user) + return requiredRoles.some((roleCode) => roleCodes.includes(roleCode)) +} + +export function getAccessibleViewIds(user) { + return DEFAULT_APP_VIEW_ORDER.filter((viewId) => canAccessAppView(user, viewId)) +} + +export function filterNavItemsByAccess(navItems, user) { + return navItems.filter((item) => canAccessAppView(user, item.id)) +} + +export function resolveDefaultAuthorizedRoute(user) { + const firstVisibleView = getAccessibleViewIds(user)[0] + return { name: `app-${firstVisibleView || 'workbench'}` } +} diff --git a/web/src/views/AppShellRouteView.vue b/web/src/views/AppShellRouteView.vue index 988cd86..3cb8c4a 100644 --- a/web/src/views/AppShellRouteView.vue +++ b/web/src/views/AppShellRouteView.vue @@ -1,7 +1,7 @@