This commit is contained in:
2024-04-26 03:55:21 +00:00
parent 93f58648ed
commit b71f0054a0
20 changed files with 1221 additions and 0 deletions

1
fuware/__init__.py Normal file
View File

@ -0,0 +1 @@
__version__ = "develop"

15
fuware/const.py Normal file
View File

@ -0,0 +1,15 @@
import os
from dotenv import load_dotenv
load_dotenv()
SERCET_KEY = b"oWNhXlfo666JlMHk6UHYxeNB6z_CA2MisDDZJe4N0yc="
COOKIE_KEY = os.getenv('VITE_LOGIN_KEY') or '7fo24CMyIc'
# URL_DATABASE = "postgresql://{0}:{1}@{2}:{3}/{4}".format(
# os.getenv('LOL_DB_USER'),
# os.getenv('LOL_DB_PASSWORD'),
# os.getenv('LOL_DB_HOST'),
# os.getenv('LOL_DB_PORT'),
# os.getenv('LOL_DB_NAME'),
# )
URL_DATABASE = "sqlite:///./test.db"

1
fuware/db/__init__.py Normal file
View File

@ -0,0 +1 @@
from .db_setup import *

View File

@ -0,0 +1 @@
from .user import *

View File

@ -0,0 +1,20 @@
from sqlalchemy.orm import Session
from db.models import User
from ultis import get_password_hash
import schemas
def get_user(db: Session, user_id: str):
return db.query(User).filter(User.id == user_id).first()
def get_user_by_username(db: Session, usn: str):
return db.query(User).filter(User.username == usn).first()
def get_users(db: Session, skip: int = 0, limit: int = 100):
return db.query(User).offset(skip).limit(limit).all()
def create_user(db: Session, user: schemas.UserCreate):
db_user = User(username=user.username, password=get_password_hash(user.password), name=user.name)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user

17
fuware/db/db_setup.py Normal file
View File

@ -0,0 +1,17 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from const import URL_DATABASE
engine = create_engine(URL_DATABASE)
SessionLocal = sessionmaker(autocommit=False ,autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

View File

@ -0,0 +1 @@
from .user import *

View File

@ -0,0 +1,8 @@
from datetime import datetime
from sqlalchemy import Column, DateTime
from sqlalchemy.orm import declarative_mixin
@declarative_mixin
class Timestamp:
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
updated_at = Column(DateTime, default=datetime.utcnow, nullable=False)

15
fuware/db/models/user.py Normal file
View File

@ -0,0 +1,15 @@
from db import Base
from sqlalchemy import Boolean, Column, String
from .mixins import Timestamp
from sqlalchemy.dialects.postgresql import UUID
import uuid
class User(Base, Timestamp):
__tablename__ = 'users'
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
username = Column(String(100), unique=True, index=True, nullable=False)
password = Column(String, index=True, nullable=False)
name = Column(String, index=True, nullable=True)
is_admin = Column(Boolean, default=False)
is_lock = Column(Boolean, default=False)

34
fuware/main.py Normal file
View File

@ -0,0 +1,34 @@
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
from routes import authR, userR
# from db import engine, models
# from sqlalchemy import event
# from db.seeds import initialize_table
import uvicorn
# event.listen(models.User.__table__, 'after_create', initialize_table)
app = FastAPI()
# models.Base.metadata.create_all(bind=engine)
@app.exception_handler(HTTPException)
async def unicorn_exception_handler(request: Request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content={"status": exc.status_code, "data": exc.detail},
)
app.include_router(authR.authRouter)
app.include_router(userR.userRouter)
def main():
uvicorn.run(
"main:app",
port=8000,
host="0.0.0.0",
reload=True
)
if __name__ == '__main__':
main()

50
fuware/routes/authR.py Normal file
View File

@ -0,0 +1,50 @@
from typing import Any
from fastapi import APIRouter, HTTPException, Response, Request, Depends
from fastapi.encoders import jsonable_encoder
from schemas import ReturnValue, User, UserCreate, UserRequest
from ultis import root_api_path_build, encryptString, decryptString, verify_password
from const import COOKIE_KEY
from sqlalchemy.orm import Session
from db.controller import get_user_by_username, create_user
from db import get_db
authRouter=APIRouter(prefix=root_api_path_build('/auth'))
@authRouter.put('/register')
def register_user(user: UserCreate, db: Session = Depends(get_db)) -> ReturnValue[Any]:
db_user = get_user_by_username(db=db, usn=user.username)
if db_user:
raise HTTPException(status_code=400, detail="Username already registered!")
user_return = create_user(db=db, user=user)
return ReturnValue(status=200, data=jsonable_encoder(user_return))
@authRouter.post('/login', response_model=ReturnValue[User])
def user_login(user: UserRequest, response: Response, db: Session = Depends(get_db)) -> ReturnValue[Any]:
db_user = get_user_by_username(db, user.username)
if not db_user:
raise HTTPException(status_code=401, detail="Your username or password input is wrong!")
if not verify_password(user.password, db_user.password):
raise HTTPException(status_code=401, detail="Your username or password input is wrong!")
if db_user.is_lock is True:
raise HTTPException(status_code=401, detail="Your Account is banned")
cookieEncode = encryptString(user.username + ',' + user.password)
response.set_cookie(key=COOKIE_KEY, value=cookieEncode.decode('utf-8'))
return ReturnValue(status=200, data=jsonable_encoder(db_user))
@authRouter.get('/logout')
def user_logout(response: Response) -> ReturnValue[Any]:
response.delete_cookie(key=COOKIE_KEY)
return ReturnValue(status=200, data='Logged out')
def get_auth_user(request: Request, db: Session = Depends(get_db)):
"""verify that user has a valid session"""
session_id = request.cookies.get(COOKIE_KEY)
if not session_id:
raise HTTPException(status_code=401, detail="Unauthorized")
decrypt_user = decryptString(session_id).split(',')
db_user = get_user_by_username(db, decrypt_user[0])
if not db_user:
raise HTTPException(status_code=403)
if not verify_password(decrypt_user[1], db_user.password):
raise HTTPException(status_code=401, detail="Your username or password input is wrong!")
return True

11
fuware/routes/userR.py Normal file
View File

@ -0,0 +1,11 @@
from typing import Any
from fastapi import APIRouter, Depends
from schemas import ReturnValue
from ultis import root_api_path_build
from routes import authR
userRouter=APIRouter(prefix=root_api_path_build('/user'))
@userRouter.get('/get-data/', dependencies=[Depends(authR.get_auth_user)])
def get_data(url: str = '') -> ReturnValue[Any]:
return ReturnValue(status=200, data=url)

View File

@ -0,0 +1,2 @@
from .common import *
from .user import *

8
fuware/schemas/common.py Normal file
View File

@ -0,0 +1,8 @@
from typing import Generic, TypeVar
from pydantic import BaseModel
T = TypeVar('T')
class ReturnValue(BaseModel, Generic[T]):
status: int
data: T

24
fuware/schemas/user.py Normal file
View File

@ -0,0 +1,24 @@
from datetime import datetime
from pydantic import BaseModel
from fastapi import Form
class UserBase(BaseModel):
username: str = Form(...)
class UserRequest(UserBase):
password: str = Form(...)
class UserCreate(UserRequest):
password: str = Form(...)
name: str
class User(UserBase):
id: str
name: str
is_admin: bool
is_lock: bool
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True

23
fuware/ultis.py Normal file
View File

@ -0,0 +1,23 @@
from cryptography.fernet import Fernet
from passlib.context import CryptContext
from const import SERCET_KEY
root_path = '/api'
pwd_context = CryptContext(schemes=["sha256_crypt"], deprecated="auto")
def root_api_path_build(path):
return root_path + path
def encryptString(strEncode: str):
fernet = Fernet(SERCET_KEY)
return fernet.encrypt(strEncode.encode())
def decryptString(strDecode: str):
fernet = Fernet(SERCET_KEY)
return fernet.decrypt(strDecode).decode()
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password):
return pwd_context.hash(password)