From 206bbe222ff5452a2895b81db9d33d08f78ae222 Mon Sep 17 00:00:00 2001 From: Henglay-Eung Date: Wed, 19 Feb 2025 15:43:37 -0800 Subject: [PATCH] Add dynamic user authentication --- backend/controller/plant_controller.py | 20 ++++++------- backend/dal/user_dal.py | 41 ++++++++++++++++++++++++++ backend/repository/user_repository.py | 9 ++++++ backend/schemas/user_schema.py | 5 ++++ backend/services/user_service.py | 15 ++++++++++ 5 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 backend/dal/user_dal.py create mode 100644 backend/repository/user_repository.py create mode 100644 backend/schemas/user_schema.py create mode 100644 backend/services/user_service.py diff --git a/backend/controller/plant_controller.py b/backend/controller/plant_controller.py index 3bd4743..9c27355 100644 --- a/backend/controller/plant_controller.py +++ b/backend/controller/plant_controller.py @@ -1,27 +1,26 @@ -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, HTTPException from schemas.plant_schema import PlantSchema +from schemas.user_schema import UserSchema from services.plant_service import get_service, PlantService from fastapi import Depends from fastapi.responses import JSONResponse from fastapi.security import HTTPBasic, HTTPBasicCredentials - +from services.user_service import get_user_service, UserService create_plant = APIRouter() security = HTTPBasic() -user = { - "admin": "admin", - "user": "admin" -} -def verify_credentials(credentials: HTTPBasicCredentials = Depends(security)): +def verify_credentials(credentials: HTTPBasicCredentials = Depends(security), user_service: UserService = Depends(get_user_service)): username = credentials.username password = credentials.password - if user.get(username) != password: + user_schema = UserSchema(username=username, password=password) + print(user_service.verify_user(user_schema)) + if user_service.verify_user(user_schema) == 0: raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, + status_code= 401, detail="Invalid credentials", headers={"WWW-Authenticate": "Basic"}, ) @@ -45,4 +44,5 @@ def create_plant_entry(plant: PlantSchema, service: PlantService = Depends(get_s except Exception as e: # If an unexpected error occurs during processing, return a 500 status code - return JSONResponse(status_code=500, content={"status": "error", "error": f"Unexpected error: {str(e)}"}) \ No newline at end of file + return JSONResponse(status_code=500, content={"status": "error", "error": f"Unexpected error: {str(e)}"}) + \ No newline at end of file diff --git a/backend/dal/user_dal.py b/backend/dal/user_dal.py new file mode 100644 index 0000000..ec5d209 --- /dev/null +++ b/backend/dal/user_dal.py @@ -0,0 +1,41 @@ +from config.database import get_connection, release_connection +from schemas.user_schema import UserSchema +import psycopg2 +from psycopg2 import DatabaseError + +class UserDAL: + def __init__(self): + self.conn = get_connection() + self.cursor = self.conn.cursor() + + def verify_user(self, user: UserSchema): + try: + if not user.username or not user.password: + raise ValueError("Username and password must not be empty.") + + self.cursor.execute(""" + SELECT EXISTS ( + SELECT 1 FROM users WHERE username = %s AND password = %s + ); + """, (user.username, user.password)) + + return self.cursor.fetchone()[0] # Returns True or False + + except (psycopg2.Error, DatabaseError) as db_error: + self.conn.rollback() + print(f"Database error: {db_error}") + return {"status": "error", "error": str(db_error)} + + except ValueError as val_error: + print(f"Input error: {val_error}") + return {"status": "error", "error": str(val_error)} + + except Exception as e: + self.conn.rollback() + print(f"Unexpected error: {e}") + return {"status": "error", "error": str(e)} + + def __del__(self): + """ Ensure the connection is closed when the object is destroyed. """ + if self.conn: + release_connection(self.conn) diff --git a/backend/repository/user_repository.py b/backend/repository/user_repository.py new file mode 100644 index 0000000..f857ffa --- /dev/null +++ b/backend/repository/user_repository.py @@ -0,0 +1,9 @@ +from dal.user_dal import UserDAL +from schemas.user_schema import UserSchema + +class UserRepository: + def __init__(self, dal: UserDAL): + self.dal = dal + + def verify_user(self, user: UserSchema): + return self.dal.verify_user(user) \ No newline at end of file diff --git a/backend/schemas/user_schema.py b/backend/schemas/user_schema.py new file mode 100644 index 0000000..ce8a91e --- /dev/null +++ b/backend/schemas/user_schema.py @@ -0,0 +1,5 @@ +from pydantic import BaseModel + +class UserSchema(BaseModel): + username: str + password: str \ No newline at end of file diff --git a/backend/services/user_service.py b/backend/services/user_service.py new file mode 100644 index 0000000..21bc87a --- /dev/null +++ b/backend/services/user_service.py @@ -0,0 +1,15 @@ +from repository.user_repository import UserRepository +from dal.user_dal import UserDAL +from schemas.user_schema import UserSchema + +class UserService: + def __init__(self, repository: UserRepository): + self.repository = repository + + def verify_user(self, user: UserSchema): + return self.repository.verify_user(user) + +def get_user_service(): + dal = UserDAL() + repository = UserRepository(dal) + return UserService(repository) \ No newline at end of file