Coverage for docs/docs_src/user_guide/adapters/fastapi/security/main_1_simple.py: 84%
38 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-19 12:16 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-19 12:16 +0000
1from typing import Annotated, Any, Optional, Union 1aefghibcd
3from fastapi import Depends, FastAPI, HTTPException, status 1aefghibcd
4from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm 1aefghibcd
5from pydantic import BaseModel 1aefghibcd
7from fastagency.adapters.fastapi import FastAPIAdapter 1aefghibcd
9from .workflows import wf 1aefghibcd
11app = FastAPI(title="FastAPI with FastAgency") 1aefghibcd
13################################################################################
14#
15# Taken from https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/
16#
18fake_users_db = { 1aefghibcd
19 "johndoe": {
20 "username": "johndoe",
21 "full_name": "John Doe",
22 "email": "johndoe@example.com",
23 "hashed_password": "fakehashedsecret", # pragma: allowlist secret
24 "disabled": False,
25 },
26 "alice": {
27 "username": "alice",
28 "full_name": "Alice Wonderson",
29 "email": "alice@example.com",
30 "hashed_password": "fakehashedsecret2", # pragma: allowlist secret
31 "disabled": True,
32 },
33}
36def fake_hash_password(password: str) -> str: 1aefghibcd
37 return "fakehashed" + password 1abcd
40oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") 1aefghibcd
43class User(BaseModel): 1aefghibcd
44 username: str 1aefghibcd
45 email: Union[str, None] = None 1aefghibcd
46 full_name: Union[str, None] = None 1aefghibcd
47 disabled: Union[bool, None] = None 1aefghibcd
50class UserInDB(User): 1aefghibcd
51 hashed_password: str 1aefghibcd
54def get_user(db: dict[str, Any], username: str) -> Optional[UserInDB]: 1aefghibcd
55 if username in db: 55 ↛ 58line 55 didn't jump to line 58 because the condition on line 55 was always true1abcd
56 user_dict = db[username] 1abcd
57 return UserInDB(**user_dict) 1abcd
58 return None
61def fake_decode_token(token: str) -> Optional[UserInDB]: 1aefghibcd
62 # This doesn't provide any security at all
63 # Check the next version
64 user = get_user(fake_users_db, token) 1abcd
65 return user 1abcd
68async def get_current_user( 1aefghibcd
69 token: Annotated[str, Depends(oauth2_scheme)],
70) -> Optional[User]:
71 user = fake_decode_token(token) 1abcd
72 if not user: 72 ↛ 73line 72 didn't jump to line 73 because the condition on line 72 was never true1abcd
73 raise HTTPException(
74 status_code=status.HTTP_401_UNAUTHORIZED,
75 detail="Invalid authentication credentials",
76 headers={"WWW-Authenticate": "Bearer"},
77 )
78 return user 1abcd
81async def get_current_active_user( 1aefghibcd
82 current_user: Annotated[User, Depends(get_current_user)],
83) -> Optional[User]:
84 if current_user.disabled: 84 ↛ 85line 84 didn't jump to line 85 because the condition on line 84 was never true1abcd
85 raise HTTPException(status_code=400, detail="Inactive user")
86 return current_user 1abcd
89@app.post("/token") 1aefghibcd
90async def login( 1aefghibcd
91 form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
92) -> dict[str, str]:
93 user_dict = fake_users_db.get(form_data.username) 1abcd
94 if not user_dict: 1abcd
95 raise HTTPException(status_code=400, detail="Incorrect username or password")
96 user = UserInDB(**user_dict) 1abcd
97 hashed_password = fake_hash_password(form_data.password) 1abcd
98 if not hashed_password == user.hashed_password: 1abcd
99 raise HTTPException(status_code=400, detail="Incorrect username or password")
101 return {"access_token": user.username, "token_type": "bearer"} 1abcd
104#
105# End of code from https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/
106#
107################################################################################
110def get_user_id( 1aefghibcd
111 current_user: Annotated[User, Depends(get_current_active_user)],
112) -> Optional[str]:
113 return current_user.username 1abcd
116adapter = FastAPIAdapter(provider=wf, get_user_id=get_user_id) 1aefghibcd
117app.include_router(adapter.router) 1aefghibcd
120# this is optional, but we would like to see the list of available workflows
121@app.get("/") 1aefghibcd
122def read_root() -> dict[str, dict[str, str]]: 1aefghibcd
123 return {"Workflows": {name: wf.get_description(name) for name in wf.names}}