fix(auth): 登录失败、错误提示中文化、记住我 checkbox 样式
- 重置 admin 密码哈希为 Admin@123 - local.py / auth.py / dependencies.py 面向用户的错误提示改为中文 - LoginView 为记住我 checkbox 添加显式方形/主色样式
This commit is contained in:
parent
af2de993d8
commit
96c15146d5
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue