diff --git a/.env b/.env new file mode 100644 index 0000000..3684748 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +ALGORITHM=HS256 +DATABASE_URL=sqlite:///test.db +SECRET_KEY=your_secret_key diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 0000000..b7ff6d8 --- /dev/null +++ b/api/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/11/19 下午7:26 +# @Author : 河瞬 +# @FileName: __init__.py.py +# @Software: PyCharm diff --git a/api/login_reg.py b/api/login_reg.py new file mode 100644 index 0000000..971b66c --- /dev/null +++ b/api/login_reg.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/11/19 下午7:27 +# @Author : 河瞬 +# @FileName: login_reg.py +# @Software: PyCharm +from fastapi import HTTPException, Response, Depends, APIRouter +from typing import Optional, Annotated +from datetime import datetime, timedelta +from jose import JWTError, jwt + +from sqlmodel import select + +from models import Tenant, User, Project +from dependencies import * + +router = APIRouter() + + +# 生成JWT token +def create_access_token(data: dict, expires_delta: Optional[timedelta] = None, settings: SettingsDep = SettingsDep): + to_encode = data.copy() + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(minutes=15) + to_encode.update({"exp": expire}) + print(settings, type(settings)) + encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) + return encoded_jwt + + +# 登录路由 +@router.post("/api/s1/login") +async def login(response: Response, user_data: dict, session: SessionDep): + # 查询用户 + user = session.exec(select(User).where(User.username == user_data['username'])).first() + + # 验证用户名和密码 + if not user or user.password != user_data['password']: + raise HTTPException(status_code=401, detail="Login failed") + + # 生成JWT token + token = create_access_token(data={"id": user.id, "role": user.role, "tanant_id": user.tenant.id}) + + # 设置cookie + response.set_cookie(key="session_token", value=token, httponly=True) + + # 关闭数据库会话 + session.close() + + return {"message": f"Login successful"} diff --git a/api/manage_project.py b/api/manage_project.py new file mode 100644 index 0000000..d833e8d --- /dev/null +++ b/api/manage_project.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/11/19 下午8:05 +# @FileName: manage_project.py +# @Software: PyCharm +from fastapi import HTTPException, Response, Depends, APIRouter +from typing import Optional, Annotated +from datetime import datetime, timedelta +from jose import JWTError, jwt + +from sqlmodel import select + +from models import Tenant, User, Project +from dependencies import * + +router = APIRouter() + + +@router.get(...) +def example(): + return "hello" diff --git a/api/manage_tanant.py b/api/manage_tanant.py new file mode 100644 index 0000000..7934876 --- /dev/null +++ b/api/manage_tanant.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/11/19 下午8:04 +# @FileName: manage_tanant.py +# @Software: PyCharm +from fastapi import HTTPException, Response, Depends, APIRouter +from typing import Optional, Annotated +from datetime import datetime, timedelta +from jose import JWTError, jwt + +from sqlmodel import select + +from models import Tenant, User, Project +from dependencies import * + +router = APIRouter() + + +@router.get(...) +def example(): + return "hello" diff --git a/api/manage_user.py b/api/manage_user.py new file mode 100644 index 0000000..59cf9ad --- /dev/null +++ b/api/manage_user.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/11/19 下午8:05 +# @Author : 河瞬 +# @FileName: manage_user.py +# @Software: PyCharm +from fastapi import HTTPException, Response, Depends, APIRouter +from typing import Optional, Annotated +from datetime import datetime, timedelta +from jose import JWTError, jwt + +from sqlmodel import select + +from models import Tenant, User, Project +from dependencies import * + +router = APIRouter() + + +@router.get(...) +def example(): + return "hello" diff --git a/config.py b/config.py new file mode 100644 index 0000000..cc00044 --- /dev/null +++ b/config.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/11/19 下午7:30 +# @Author : 河瞬 +# @FileName: config.py +# @Software: PyCharm +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + ALGORITHM: str = "HS256" + DATABASE_URL: str = "sqlite:///test.db" + SECRET_KEY: str = "your_secret_key" + + class Config: + env_file = ".env" + +if __name__ == '__main__': + print(Settings().ALGORITHM) \ No newline at end of file diff --git a/database.py b/database.py index b4bff52..d9cb5c1 100644 --- a/database.py +++ b/database.py @@ -5,11 +5,12 @@ # @Software: PyCharm from sqlmodel import SQLModel, create_engine -sqlite_file_name = "test.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" +from config import Settings + +sqlite_url = Settings().DATABASE_URL engine = create_engine(sqlite_url) def create_db_and_tables(): - SQLModel.metadata.create_all(engine) \ No newline at end of file + SQLModel.metadata.create_all(engine) diff --git a/dependencies.py b/dependencies.py new file mode 100644 index 0000000..d5e01e7 --- /dev/null +++ b/dependencies.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# @Time : 2024/11/19 下午7:33 +# @Author : 河瞬 +# @FileName: dependencies.py +# @Software: PyCharm +from typing import Annotated +from fastapi import Depends +from database import engine +from sqlmodel import Session +from config import Settings + + +def get_session(): + with Session(engine) as session: + yield session + + +def get_settings(): + return Settings() + + +SessionDep = Annotated[Session, Depends(get_session)] + +SettingsDep = get_settings() diff --git a/main.py b/main.py index 7f5befc..cdd3238 100644 --- a/main.py +++ b/main.py @@ -9,6 +9,8 @@ from sqlmodel import Session, select from database import create_db_and_tables, engine from models import Tenant, User, Project +from dependencies import * +from api import login_reg, manage_project, manage_tanant, manage_user # 用于生成和验证JWT的密钥 SECRET_KEY = "your_secret_key" @@ -24,44 +26,8 @@ async def lifespan(app: FastAPI): yield -def get_session(): - with Session(engine) as session: - yield session - - -# 生成JWT token -def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.utcnow() + expires_delta - else: - expire = datetime.utcnow() + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - app = FastAPI(lifespan=lifespan) -SessionDep = Annotated[Session, Depends(get_session)] - - -# 登录路由 -@app.post("/api/s1/login") -async def login(response: Response, user_data: dict, session: SessionDep): - # 查询用户 - user = session.exec(select(User).where(User.username == user_data['username'])).first() - - # 验证用户名和密码 - if not user or user.password != user_data['password']: - raise HTTPException(status_code=401, detail="Login failed") - - # 生成JWT token - token = create_access_token(data={"id": user.id, "role": user.role, "tanant_id": user.tenant.id}) - - # 设置cookie - response.set_cookie(key="session_token", value=token, httponly=True) - - # 关闭数据库会话 - session.close() - - return {"message": f"Login successful"} +app.include_router(login_reg.router) +app.include_router(manage_tanant.router) +app.include_router(manage_user.router) +app.include_router(manage_project.router) diff --git a/requirements.txt b/requirements.txt index 130c9f2..f96eaeb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ fastapi~=0.115.5 -SQLAlchemy~=2.0.36 python-jose~=3.3.0 -uvicorn~=0.32.0 \ No newline at end of file +uvicorn~=0.32.0 +pydantic~=2.9.2 +pydantic-settings~=2.6.1 +sqlmodel~=0.0.22 \ No newline at end of file diff --git a/test.db b/test.db deleted file mode 100644 index 5a708e9..0000000 Binary files a/test.db and /dev/null differ