-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Kalim
authored and
Kalim
committed
Sep 17, 2023
0 parents
commit 0ac4791
Showing
11 changed files
with
268 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Authentication App | ||
|
||
This is a flexible authentication app that allows you to choose between MongoDB and PostgreSQL as the backend database. | ||
|
||
## Installation | ||
|
||
1. Clone this repository: | ||
``` | ||
git clone https://github.com/yourusername/my_authentication_app.git | ||
cd authentication_app | ||
``` | ||
|
||
|
||
2. Create a virtual environment (optional but recommended: | ||
``` | ||
python -m venv venv | ||
source venv/bin/activate | ||
``` | ||
|
||
|
||
3. Install the required dependencies: | ||
|
||
``` | ||
pip install -r requirements.txt | ||
``` | ||
|
||
|
||
## Configuration | ||
|
||
You can configure the choice of backend database in the `authentication/config.py` file by setting the `use_database` parameter to either "postgresql" or "mongodb." | ||
|
||
## Usage | ||
|
||
1. Run the application: | ||
|
||
uvicorn my_authentication_app.main:app --reload | ||
|
||
|
||
2. Access the Swagger documentation at http://localhost:8000/docs to interact with the API endpoints. | ||
|
||
|
||
|
||
## Integrate with any applications | ||
|
||
``` | ||
from authentication_app.authentication.auth import Auth | ||
from fastapi import Depends, FastAPI | ||
app = FastAPI() | ||
auth = Auth() # Create an instance of the Auth class | ||
@app.get("/protected", response_model=str) | ||
def protected_endpoint(current_user: str = Depends(auth.get_current_user)): | ||
# Your protected endpoint logic here | ||
return "This is a protected endpoint." | ||
``` | ||
|
||
|
||
## License | ||
|
||
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. | ||
|
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# my_authentication_app/authentication/auth.py | ||
from datetime import datetime, timedelta | ||
from jose import JWTError, jwt | ||
from passlib.context import CryptContext | ||
from fastapi import HTTPException, Depends, Security | ||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm | ||
from sqlalchemy.orm import Session | ||
from pymongo.collection import Collection | ||
from pymongo.database import Database | ||
from pydantic import BaseModel | ||
|
||
from .config import config | ||
from .db_models import UserDB as PostgresUserDB | ||
from .mongodb_models import UserDB as MongoDBUserDB | ||
from .database import Database | ||
|
||
# OAuth2PasswordBearer for token authentication | ||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") | ||
|
||
# Pydantic models | ||
class UserCreate(BaseModel): | ||
username: str | ||
password: str | ||
|
||
class User(BaseModel): | ||
username: str | ||
is_superuser: bool | ||
|
||
class Token(BaseModel): | ||
access_token: str | ||
token_type: str | ||
|
||
# Password hashing | ||
passlib_context = CryptContext(schemes=["bcrypt"], deprecated="auto") | ||
|
||
# Authentication class | ||
class Auth: | ||
def __init__(self, db: Database): | ||
self.db = db | ||
|
||
def create_user(self, user: UserCreate, is_superuser: bool = False): | ||
if self.db.config.use_database == "postgresql": | ||
# Create user in PostgreSQL | ||
hashed_password = self.get_password_hash(user.password) | ||
db_user = PostgresUserDB(username=user.username, hashed_password=hashed_password, is_superuser=is_superuser) | ||
db = self.db.get_session() | ||
db.add(db_user) | ||
db.commit() | ||
db.refresh(db_user) | ||
return db_user | ||
elif self.db.config.use_database == "mongodb": | ||
user_data = MongoDBUserCreate(username=user.username, hashed_password=user.password, is_superuser=is_superuser) | ||
user_id = self.db.user_collection.insert_one(user_data.dict()).inserted_id | ||
return user_id | ||
else: | ||
raise ValueError("Invalid database type. Please choose 'postgresql' or 'mongodb'.") | ||
|
||
def create_access_token(self, data: dict, expires_delta: timedelta = None): | ||
to_encode = data.copy() | ||
if expires_delta: | ||
expire = datetime.utcnow() + expires_delta | ||
else: | ||
expire = datetime.utcnow() + timedelta(minutes=config.access_token_expire_minutes) | ||
to_encode.update({"exp": expire}) | ||
encoded_jwt = jwt.encode(to_encode, config.secret_key, algorithm=config.algorithm) | ||
return encoded_jwt | ||
|
||
def verify_password(self, plain_password, hashed_password): | ||
return passlib_context.verify(plain_password, hashed_password) | ||
|
||
def get_password_hash(self, password): | ||
return passlib_context.hash(password) | ||
|
||
def get_current_user(self, token: str = Depends(oauth2_scheme)): | ||
try: | ||
payload = jwt.decode(token, config.secret_key, algorithms=[config.algorithm]) | ||
username: str = payload.get("sub") | ||
if username is None: | ||
raise HTTPException(status_code=401, detail="Could not validate credentials") | ||
token_data = TokenData(username=username) | ||
except JWTError: | ||
raise HTTPException(status_code=401, detail="Could not validate credentials") | ||
|
||
if self.db.config.use_database == "postgresql": | ||
db_user = self.db.get_session().query(PostgresUserDB).filter(PostgresUserDB.username == token_data.username).first() | ||
if db_user is None: | ||
raise HTTPException(status_code=401, detail="User not found") | ||
return User(username=db_user.username, is_superuser=db_user.is_superuser) | ||
elif self.db.config.use_database == "mongodb": | ||
user_data = self.db.user_collection.find_one({"username": token_data.username}) | ||
if user_data is None: | ||
raise HTTPException(status_code=401, detail="User not found") | ||
user_db = MongoDBUserDB(**user_data) | ||
return User(username=user_db.username, is_superuser=user_db.is_superuser) | ||
else: | ||
raise ValueError("Invalid database type. Please choose 'postgresql' or 'mongodb'.") | ||
|
||
def get_current_active_user(current_user: User = Security(Auth.get_current_user, scopes=["superuser"])): | ||
# Check user permissions | ||
if not current_user.is_superuser: | ||
raise HTTPException(status_code=403, detail="Insufficient permissions") | ||
return current_user |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# my_authentication_app/authentication/config.py | ||
from pydantic import BaseSettings | ||
|
||
class AuthConfig(BaseSettings): | ||
secret_key: str = "your-secret-key" # Replace with a secure secret key | ||
algorithm: str = "HS256" | ||
access_token_expire_minutes: int = 60 | ||
use_database: str = "postgresql" # Default to PostgreSQL | ||
|
||
# PostgreSQL configuration | ||
postgresql_uri: str = "postgresql://username:password@localhost/database_name" | ||
|
||
# MongoDB configuration | ||
mongodb_uri: str = "mongodb://localhost:27017/" | ||
mongodb_db_name: str = "my_auth_db" | ||
|
||
config = AuthConfig() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# my_authentication_app/authentication/database.py | ||
from sqlalchemy import create_engine | ||
from sqlalchemy.orm import sessionmaker | ||
from pymongo import MongoClient | ||
from pymongo.collection import Collection | ||
from pymongo.database import Database | ||
from pydantic import BaseSettings | ||
import config | ||
class Database: | ||
def __init__(self, config: AuthConfig): | ||
self.config = config | ||
|
||
def get_session(self): | ||
if self.config.use_database == "postgresql": | ||
engine = create_engine(self.config.postgresql_uri) | ||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) | ||
return SessionLocal() | ||
elif self.config.use_database == "mongodb": | ||
client = MongoClient(self.config.mongodb_uri) | ||
db = client[self.config.mongodb_db_name] | ||
return db | ||
else: | ||
raise ValueError("Invalid database type. Please choose 'postgresql' or 'mongodb'.") | ||
|
||
# config = AuthConfig() | ||
db = Database(config) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# my_authentication_app/authentication/mongodb_models.py | ||
from pydantic import BaseModel | ||
from bson import ObjectId | ||
from typing import Optional | ||
|
||
class MongoDBUserDB(BaseModel): | ||
id: Optional[ObjectId] # Optional for new user creation | ||
username: str | ||
hashed_password: str | ||
is_superuser: bool | ||
|
||
class MongoDBTokenDB(BaseModel): | ||
id: ObjectId | ||
access_token: str | ||
token_type: str | ||
|
||
class MongoDBUserCreate(BaseModel): | ||
username: str | ||
hashed_password: str | ||
is_superuser: bool |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# my_authentication_app/authentication/postgresql_models.py | ||
from sqlalchemy import Column, Integer, String, Boolean | ||
from sqlalchemy.ext.declarative import declarative_base | ||
|
||
Base = declarative_base() | ||
|
||
class UserDB(Base): | ||
__tablename__ = "users" | ||
|
||
id = Column(Integer, primary_key=True, index=True) | ||
username = Column(String, unique=True, index=True) | ||
hashed_password = Column(String) | ||
is_superuser = Column(Boolean, default=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
fastapi==0.68.1 | ||
uvicorn==0.15.0 | ||
passlib[bcrypt]==1.7.4 | ||
pydantic==1.8.3 | ||
jose[cryptography]==1.3.2 | ||
asyncpg==0.24.0 # PostgreSQL driver (optional) | ||
pymongo==3.12.1 # MongoDB driver (optional) | ||
python-multipart==0.0.5 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from setuptools import setup, find_packages | ||
|
||
setup( | ||
name="authentication_app", | ||
version="0.1", | ||
packages=find_packages(), | ||
install_requires=[ | ||
"fastapi==0.68.1", | ||
"uvicorn==0.15.0", | ||
"passlib[bcrypt]==1.7.4", | ||
"pydantic==1.8.3", | ||
"jose[cryptography]==1.3.2", | ||
"asyncpg==0.24.0", # PostgreSQL driver (optional) | ||
"pymongo==3.12.1", # MongoDB driver (optional) | ||
"python-multipart==0.0.5", | ||
], | ||
) |