Ali2206 commited on
Commit
77b0666
·
verified ·
1 Parent(s): cae18ab

Update core/security.py

Browse files
Files changed (1) hide show
  1. core/security.py +59 -68
core/security.py CHANGED
@@ -1,89 +1,80 @@
1
- # core/security.py
2
  from datetime import datetime, timedelta
3
- from passlib.context import CryptContext
4
- from jose import jwt, JWTError
5
- from fastapi import Depends, HTTPException, status
6
  from fastapi.security import OAuth2PasswordBearer
7
- from core.config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
8
- from db.mongo import users_collection
 
9
  import logging
10
- from fastapi import Request
11
 
12
  logger = logging.getLogger(__name__)
13
 
14
- # OAuth2 setup
15
  oauth2_scheme = OAuth2PasswordBearer(
16
- tokenUrl="/auth/login",
17
  scheme_name="JWT"
18
  )
19
 
20
- # Password hashing context
21
- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
22
-
23
- def hash_password(password: str) -> str:
24
- return pwd_context.hash(password)
25
-
26
- def verify_password(plain: str, hashed: str) -> bool:
27
- return pwd_context.verify(plain, hashed)
28
-
29
- def create_access_token(data: dict, expires_delta: timedelta = None):
30
- to_encode = data.copy()
31
- expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
32
- to_encode.update({"exp": expire, "iat": datetime.utcnow()})
33
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
34
- logger.debug(f"Created JWT for {data.get('sub')}, expires at {expire}")
35
- return encoded_jwt
36
 
37
- async def get_current_user(request: Request, token: str = Depends(oauth2_scheme)):
38
- auth_header = request.headers.get("Authorization", "No Authorization header")
39
- logger.debug(f"Raw Authorization header: {auth_header}")
40
- logger.debug(f"Processed token: {token[:10]}... if present")
41
-
42
- if not token:
43
- logger.error(f"No token provided. Full headers: {dict(request.headers)}")
 
 
 
 
 
 
 
44
  raise HTTPException(
45
- status_code=status.HTTP_401_UNAUTHORIZED,
46
- detail="No token provided",
47
- headers={"WWW-Authenticate": "Bearer"}
48
  )
49
 
 
 
 
 
 
 
 
50
  try:
51
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
52
- logger.debug(f"Token payload: {payload}")
 
53
 
54
- email = payload.get("sub")
55
- if not email:
56
- logger.error("Invalid token: missing subject")
57
- raise HTTPException(
58
- status_code=status.HTTP_401_UNAUTHORIZED,
59
- detail="Invalid token: missing subject",
60
- headers={"WWW-Authenticate": "Bearer"}
61
- )
62
 
63
- exp = payload.get("exp")
64
- if exp and datetime.utcnow().timestamp() > exp:
65
- logger.error(f"Token expired for {email}")
 
 
 
 
 
 
66
  raise HTTPException(
67
  status_code=status.HTTP_401_UNAUTHORIZED,
68
- detail="Token has expired",
69
- headers={"WWW-Authenticate": "Bearer"}
70
  )
71
-
 
 
 
72
  except JWTError as e:
73
- logger.error(f"JWT decode error: {str(e)}. Token: {token[:10]}...")
74
- raise HTTPException(
75
- status_code=status.HTTP_401_UNAUTHORIZED,
76
- detail=f"Could not validate token: {str(e)}",
77
- headers={"WWW-Authenticate": "Bearer"}
78
- )
79
-
80
- user = await users_collection.find_one({"email": email})
81
- if not user:
82
- logger.error(f"User not found for email: {email}")
83
- raise HTTPException(
84
- status_code=status.HTTP_404_NOT_FOUND,
85
- detail="User not found"
86
- )
87
-
88
- logger.info(f"Authenticated user: {user['email']}, role: {user.get('role')}")
89
- return user
 
 
1
  from datetime import datetime, timedelta
2
+ from fastapi import HTTPException, status, Depends, Request
 
 
3
  from fastapi.security import OAuth2PasswordBearer
4
+ from jose import jwt, JWTError
5
+ from pydantic import BaseModel
6
+ from typing import Optional
7
  import logging
8
+ from core.config import settings
9
 
10
  logger = logging.getLogger(__name__)
11
 
 
12
  oauth2_scheme = OAuth2PasswordBearer(
13
+ tokenUrl=f"{settings.API_V1_STR}/auth/login",
14
  scheme_name="JWT"
15
  )
16
 
17
+ class TokenPayload(BaseModel):
18
+ sub: str
19
+ exp: int
20
+ iat: int
21
+ role: Optional[str] = None
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ def create_access_token(*, data: dict, expires_delta: timedelta = None) -> str:
24
+ try:
25
+ to_encode = data.copy()
26
+ expire = datetime.utcnow() + (expires_delta or timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES))
27
+ to_encode.update({"exp": expire, "iat": datetime.utcnow()})
28
+ encoded_jwt = jwt.encode(
29
+ to_encode,
30
+ settings.SECRET_KEY,
31
+ algorithm=settings.ALGORITHM
32
+ )
33
+ logger.info(f"Token created for {data.get('sub')}")
34
+ return encoded_jwt
35
+ except Exception as e:
36
+ logger.error(f"Token creation failed: {str(e)}")
37
  raise HTTPException(
38
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
39
+ detail="Token creation failed"
 
40
  )
41
 
42
+ async def verify_token(token: str = Depends(oauth2_scheme)) -> TokenPayload:
43
+ credentials_exception = HTTPException(
44
+ status_code=status.HTTP_401_UNAUTHORIZED,
45
+ detail="Could not validate credentials",
46
+ headers={"WWW-Authenticate": "Bearer"},
47
+ )
48
+
49
  try:
50
+ if not token:
51
+ logger.error("Empty token provided")
52
+ raise credentials_exception
53
 
54
+ if token.startswith("Bearer "):
55
+ token = token[7:]
56
+ logger.debug("Removed 'Bearer ' prefix from token")
 
 
 
 
 
57
 
58
+ payload = jwt.decode(
59
+ token,
60
+ settings.SECRET_KEY,
61
+ algorithms=[settings.ALGORITHM]
62
+ )
63
+ token_data = TokenPayload(**payload)
64
+
65
+ if datetime.fromtimestamp(token_data.exp) < datetime.utcnow():
66
+ logger.error("Token expired")
67
  raise HTTPException(
68
  status_code=status.HTTP_401_UNAUTHORIZED,
69
+ detail="Token expired"
 
70
  )
71
+
72
+ logger.info(f"Token verified for {token_data.sub}")
73
+ return token_data
74
+
75
  except JWTError as e:
76
+ logger.error(f"JWT validation failed: {str(e)}")
77
+ raise credentials_exception
78
+ except Exception as e:
79
+ logger.error(f"Unexpected token verification error: {str(e)}")
80
+ raise credentials_exception