diff --git a/backend/apps/system/api/login.py b/backend/apps/system/api/login.py index 9d7b87b8..0aca2934 100644 --- a/backend/apps/system/api/login.py +++ b/backend/apps/system/api/login.py @@ -1,6 +1,7 @@ from typing import Annotated from fastapi import APIRouter, Depends, HTTPException from fastapi.security import OAuth2PasswordRequestForm +from apps.system.schemas.system_schema import BaseUserDTO from common.core.deps import SessionDep from ..crud.user import authenticate from common.core.security import create_access_token @@ -14,9 +15,12 @@ def local_login( session: SessionDep, form_data: Annotated[OAuth2PasswordRequestForm, Depends()] ) -> Token: - user = authenticate(session=session, account=form_data.username, password=form_data.password) + user: BaseUserDTO = authenticate(session=session, account=form_data.username, password=form_data.password) if not user: raise HTTPException(status_code=400, detail="Incorrect account or password") + + if not user.oid or user.oid == 0: + raise HTTPException(status_code=400, detail="No associated workspace, Please contact the administrator") access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) user_dict = user.to_dict() return Token(access_token=create_access_token( diff --git a/backend/apps/system/api/user.py b/backend/apps/system/api/user.py index f73699b9..cb4e9fdb 100644 --- a/backend/apps/system/api/user.py +++ b/backend/apps/system/api/user.py @@ -1,5 +1,5 @@ from typing import Optional -from fastapi import APIRouter, Query +from fastapi import APIRouter, HTTPException, Query from sqlmodel import func, or_, select, delete as sqlmodel_delete from apps.system.crud.user import get_db_user, single_delete, user_ws_options from apps.system.models.system_model import UserWsModel @@ -99,7 +99,7 @@ async def ws_options(session: SessionDep, current_user: CurrentUser, trans: Tran async def ws_change(session: SessionDep, current_user: CurrentUser, oid: int): ws_list: list[UserWs] = await user_ws_options(session, current_user.id) if not any(x.id == oid for x in ws_list): - raise RuntimeError(f"oid [{oid}] is invalid!") + raise HTTPException(f"oid [{oid}] is invalid!") user_model: UserModel = get_db_user(session = session, user_id = current_user.id) user_model.oid = oid session.add(user_model) @@ -120,7 +120,7 @@ async def create(session: SessionDep, creator: UserCreator): user_model = UserModel.model_validate(data) #user_model.create_time = get_timestamp() user_model.language = "zh-CN" - session.add(user_model) + user_model.oid = 0 if creator.oid_list: # need to validate oid_list db_model_list = [ @@ -132,20 +132,22 @@ async def create(session: SessionDep, creator: UserCreator): for oid in creator.oid_list ] session.add_all(db_model_list) + user_model.oid = creator.oid_list[0] + session.add(user_model) session.commit() @router.put("") @clear_cache(namespace=CacheNamespace.AUTH_INFO, cacheName=CacheName.USER_INFO, keyExpression="editor.id") async def update(session: SessionDep, editor: UserEditor): user_model: UserModel = get_db_user(session = session, user_id = editor.id) - + origin_oid: int = user_model.oid del_stmt = sqlmodel_delete(UserWsModel).where(UserWsModel.uid == editor.id) session.exec(del_stmt) data = editor.model_dump(exclude_unset=True) user_model.sqlmodel_update(data) - session.add(user_model) + user_model.oid = 0 if editor.oid_list: # need to validate oid_list db_model_list = [ @@ -157,7 +159,8 @@ async def update(session: SessionDep, editor: UserEditor): for oid in editor.oid_list ] session.add_all(db_model_list) - + user_model.oid = origin_oid if origin_oid in editor.oid_list else editor.oid_list[0] + session.add(user_model) session.commit() @router.delete("/{id}") @@ -184,7 +187,7 @@ async def langChange(session: SessionDep, current_user: CurrentUser, language: U @clear_cache(namespace=CacheNamespace.AUTH_INFO, cacheName=CacheName.USER_INFO, keyExpression="id") async def pwdReset(session: SessionDep, current_user: CurrentUser, id: int): if not current_user.isAdmin: - raise RuntimeError('only for admin') + raise HTTPException('only for admin') db_user: UserModel = get_db_user(session=session, user_id=id) db_user.password = default_md5_pwd() session.add(db_user) @@ -195,7 +198,7 @@ async def pwdReset(session: SessionDep, current_user: CurrentUser, id: int): async def pwdUpdate(session: SessionDep, current_user: CurrentUser, editor: PwdEditor): db_user: UserModel = get_db_user(session=session, user_id=current_user.id) if not verify_md5pwd(editor.pwd, db_user.password): - raise RuntimeError("pwd error") + raise HTTPException("pwd error") db_user.password = md5pwd(editor.new_pwd) session.add(db_user) session.commit() \ No newline at end of file diff --git a/backend/apps/system/middleware/auth.py b/backend/apps/system/middleware/auth.py index f20fba96..4e298ab3 100644 --- a/backend/apps/system/middleware/auth.py +++ b/backend/apps/system/middleware/auth.py @@ -1,6 +1,6 @@ from typing import Optional -from fastapi import Request +from fastapi import HTTPException, Request from fastapi.responses import JSONResponse import jwt from sqlmodel import Session @@ -35,7 +35,7 @@ class TokenMiddleware(BaseHTTPMiddleware): request.state.current_user = validator[1] request.state.assistant = validator[2] return await call_next(request) - return JSONResponse({"error": f"Unauthorized:[{validator[1]}]"}, status_code=401) + return JSONResponse({"msg": f"Unauthorized:[{validator[1]}]"}, status_code=401) #validate pass tokenkey = settings.TOKEN_KEY token = request.headers.get(tokenkey) @@ -43,7 +43,7 @@ class TokenMiddleware(BaseHTTPMiddleware): if validate_pass: request.state.current_user = data return await call_next(request) - return JSONResponse({"error": f"Unauthorized:[{data}]"}, status_code=401) + return JSONResponse({"msg": f"Unauthorized:[{data}]"}, status_code=401) def is_options(self, request: Request): return request.method == "OPTIONS" @@ -62,6 +62,12 @@ class TokenMiddleware(BaseHTTPMiddleware): with Session(engine) as session: session_user = await get_user_info(session = session, user_id = token_data.id) session_user = UserInfoDTO.model_validate(session_user) + session_user = UserInfoDTO.model_validate(session_user) + if token_data.oid != session_user.oid: + raise HTTPException( + status_code=401, + detail="Default space has been changed, please login again!" + ) return True, session_user except Exception as e: return False, e diff --git a/backend/apps/system/models/user.py b/backend/apps/system/models/user.py index c5079feb..078f02d2 100644 --- a/backend/apps/system/models/user.py +++ b/backend/apps/system/models/user.py @@ -10,7 +10,7 @@ from common.utils.time import get_timestamp class BaseUserPO(SQLModel): account: str = Field(max_length=255, unique=True) - oid: int = Field(nullable=False, sa_type=BigInteger()) + oid: int = Field(nullable=False, sa_type=BigInteger(), default=0) name: str = Field(max_length=255, unique=True) password: str = Field(default_factory=default_md5_pwd, max_length=255) email: str = Field(max_length=255) diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index fc012182..2df029b4 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -121,7 +121,7 @@ const router = createRouter({ { path: '/system', component: LayoutDsl, - redirect: '/system/model', + redirect: '/system/user', children: [ { path: 'user', diff --git a/frontend/src/views/system/user/User.vue b/frontend/src/views/system/user/User.vue index 168af299..6478cab2 100644 --- a/frontend/src/views/system/user/User.vue +++ b/frontend/src/views/system/user/User.vue @@ -352,7 +352,7 @@ const state = reactive({ id: '', name: '', account: '', - oid: 1, + oid: 0, email: '', status: '', phoneNumber: '',