diff --git a/src/agentkit/server/auth/dependencies.py b/src/agentkit/server/auth/dependencies.py index fe4ca93..ef12d36 100644 --- a/src/agentkit/server/auth/dependencies.py +++ b/src/agentkit/server/auth/dependencies.py @@ -53,7 +53,7 @@ async def require_authenticated(request: Request) -> dict[str, object]: if user is None: raise HTTPException( status_code=401, - detail="Authentication required", + detail="请先登录", ) # U10 debug signal: log once per request when a legacy (no-sid) # token is in use. This makes the migration window observable in @@ -115,7 +115,7 @@ def require_permission(*permissions: Permission) -> Callable[..., object]: if high_risk: raise HTTPException( status_code=401, - detail="Authentication required for this endpoint", + detail="此接口需要登录", ) # Synthetic dev-mode user with admin-like permissions for non-high-risk return {"user_id": None, "username": "dev", "role": "admin", "dev_mode": True} @@ -125,7 +125,7 @@ def require_permission(*permissions: Permission) -> Callable[..., object]: if not has_permission(user, perm): raise HTTPException( status_code=403, - detail=f"Permission denied: requires {perm.value}", + detail=f"权限不足:需要 {perm.value} 权限", ) return user @@ -156,15 +156,15 @@ def require_any_permission(*permissions: Permission) -> Callable[..., object]: if high_risk: raise HTTPException( status_code=401, - detail="Authentication required for this endpoint", + detail="此接口需要登录", ) return {"user_id": None, "username": "dev", "role": "admin", "dev_mode": True} if not any(has_permission(user, p) for p in permissions): - needed = " or ".join(p.value for p in permissions) + needed = " 或 ".join(p.value for p in permissions) raise HTTPException( status_code=403, - detail=f"Permission denied: requires {needed}", + detail=f"权限不足:需要 {needed} 权限", ) return user @@ -198,7 +198,7 @@ async def require_terminal_authorized(request: Request) -> dict[str, object]: user_id = user.get("user_id") if not user_id: - raise HTTPException(status_code=401, detail="Authentication required") + raise HTTPException(status_code=401, detail="请先登录") db_path = await _resolve_db_path(request) async with aiosqlite.connect(str(db_path)) as db: @@ -210,15 +210,15 @@ async def require_terminal_authorized(request: Request) -> dict[str, object]: row = await cursor.fetchone() if row is None: - raise HTTPException(status_code=404, detail="User not found") + raise HTTPException(status_code=404, detail="用户不存在") if not bool(row["is_active"]): - raise HTTPException(status_code=403, detail="Account is disabled") + raise HTTPException(status_code=403, detail="账户已被禁用") if not bool(row["is_terminal_authorized"]): raise HTTPException( status_code=403, - detail="Terminal access not authorized for this account", + detail="该账户未授权使用本地终端", ) return user @@ -239,7 +239,7 @@ async def require_server_terminal_authorized(request: Request) -> dict[str, obje user_id = user.get("user_id") if not user_id: - raise HTTPException(status_code=401, detail="Authentication required") + raise HTTPException(status_code=401, detail="请先登录") db_path = await _resolve_db_path(request) async with aiosqlite.connect(str(db_path)) as db: @@ -251,15 +251,15 @@ async def require_server_terminal_authorized(request: Request) -> dict[str, obje row = await cursor.fetchone() if row is None: - raise HTTPException(status_code=404, detail="User not found") + raise HTTPException(status_code=404, detail="用户不存在") if not bool(row["is_active"]): - raise HTTPException(status_code=403, detail="Account is disabled") + raise HTTPException(status_code=403, detail="账户已被禁用") if not bool(row["is_server_terminal_authorized"]): raise HTTPException( status_code=403, - detail="Server terminal access not authorized for this account", + detail="该账户未授权使用服务端终端", ) return user diff --git a/src/agentkit/server/auth/providers/local.py b/src/agentkit/server/auth/providers/local.py index ffab51e..048c878 100644 --- a/src/agentkit/server/auth/providers/local.py +++ b/src/agentkit/server/auth/providers/local.py @@ -92,10 +92,10 @@ class LocalAuthProvider: # but has the right shape so bcrypt.checkpw doesn't short-circuit. _DUMMY_BCRYPT_HASH = "$2b$12$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZ0123" verify_password(password, _DUMMY_BCRYPT_HASH) - raise InvalidCredentials("invalid username or password") + raise InvalidCredentials("用户名或密码错误") if not verify_password(password, row["password_hash"]): - raise InvalidCredentials("invalid username or password") + raise InvalidCredentials("用户名或密码错误") return _row_to_user(row) @@ -205,10 +205,10 @@ class LocalAuthProvider: # "duplicate" message. msg = str(exc).lower() if "username" in msg: - raise ValueError(f"User with username {username!r} already exists") from exc + raise ValueError(f"用户名 {username!r} 已存在") from exc if "email" in msg: - raise ValueError(f"User with email {email!r} already exists") from exc - raise ValueError(f"User already exists: {exc}") from exc + raise ValueError(f"邮箱 {email!r} 已存在") from exc + raise ValueError(f"用户已存在: {exc}") from exc assert row is not None # we just inserted it logger.info(f"Created user {username!r} (id={user_id}) via LocalAuthProvider") diff --git a/src/agentkit/server/frontend/src/views/LoginView.vue b/src/agentkit/server/frontend/src/views/LoginView.vue index d8ff373..e0f3ba7 100644 --- a/src/agentkit/server/frontend/src/views/LoginView.vue +++ b/src/agentkit/server/frontend/src/views/LoginView.vue @@ -199,6 +199,34 @@ onMounted(async () => { margin-bottom: 16px; } +/* Checkbox 显式样式:确保方角 + 正确尺寸 + 主色选中态, + 避免 Tauri WebKit / 暗色模式下出现圆形或默认蓝色。 */ +.login-remember :deep(.ant-checkbox-inner) { + width: 16px; + height: 16px; + border-radius: 3px; + border: 1px solid var(--border-color-hover, #dfdfde); + background-color: var(--bg-primary, #ffffff); +} + +.login-remember :deep(.ant-checkbox-checked .ant-checkbox-inner) { + background-color: var(--color-primary, #1a1a1a); + border-color: var(--color-primary, #1a1a1a); +} + +.login-remember :deep(.ant-checkbox-checked .ant-checkbox-inner::after) { + border-color: var(--text-inverse, #ffffff); +} + +.login-remember :deep(.ant-checkbox-wrapper) { + color: var(--text-secondary, #4a4a4a); + font-size: var(--font-sm, 13px); +} + +.login-remember :deep(.ant-checkbox:hover .ant-checkbox-inner) { + border-color: var(--color-primary, #1a1a1a); +} + .login-footer { margin-top: 24px; text-align: center; diff --git a/src/agentkit/server/routes/auth.py b/src/agentkit/server/routes/auth.py index ac77089..7868789 100644 --- a/src/agentkit/server/routes/auth.py +++ b/src/agentkit/server/routes/auth.py @@ -376,7 +376,7 @@ async def login(payload: LoginRequest, request: Request) -> TokenResponse: raise HTTPException(status_code=401, detail=str(exc)) from exc if not user.is_active: - raise HTTPException(status_code=403, detail="Account is disabled") + raise HTTPException(status_code=403, detail="账户已被禁用") # 2. Issue tokens # The session_id is created up front (SessionService.create returns @@ -812,7 +812,7 @@ async def _sso_issue_token_pair( # SEC-1: SSO 流程必须与本地 login(auth.py:377)一致地校验 is_active, # 否则已 deprovision 的用户可通过 IDP 回调重新拿到 JWT + session。 if not bool(user_dict.get("is_active", True)): - raise HTTPException(status_code=403, detail="Account is disabled") + raise HTTPException(status_code=403, detail="账户已被禁用") db_path = await _ensure_db(request) secret = _resolve_jwt_secret(request) svc: SessionService = get_session_service() @@ -948,7 +948,7 @@ async def _require_admin( request: Request, user: dict[str, Any] = Depends(require_authenticated) ) -> dict[str, Any]: if not has_permission(user, Permission.USER_MANAGE): - raise HTTPException(status_code=403, detail="Admin permission required") + raise HTTPException(status_code=403, detail="需要管理员权限") return user