ð¡ïž FastAPI å®è·µå ¥éïŒç¬¬åæ©ç®ã§åŠã¶ ã»ãã¥ãªãã£ãšèªèšŒã®åºæ¬
ð§± ã¯ããã«
FastAPIã®æçµã¹ãããã§ã¯ãWebã¢ããªã±ãŒã·ã§ã³ã®æ ¹å¹¹ãšãªããã»ãã¥ãªãã£å¯Ÿçãã«ã€ããŠæ·±ãæãäžããŠåŠã³ãŸããã»ãã¥ãªãã£ã¯ãåã«ã¢ã¯ã»ã¹ãå¶éããã ãã§ãªãããŠãŒã¶ãŒã®ããŒã¿ãå®ããäžæ£å©çšã鲿¢ããä¿¡é Œæ§ã®é«ããµãŒãã¹ãæäŸããããã®éèŠãªèŠçŽ ã§ãã
ç¹ã«ããŠãŒã¶ãŒèªèšŒããã¹ã¯ãŒãã®æå·åãOAuth2ã«ããããŒã¯ã³ããŒã¹ã®èªå¯åŠçãããã«ã¯JSON Web TokenïŒJWTïŒãçšããããå®å
šãªèªèšŒæ¹åŒãªã©ãå®éã®ãµãŒãã¹ã§äžå¯æ¬ ãªæ©èœãå®è£
ããŠãããŸãã
ãã®ç« ã§ã¯ãFastAPIãæäŸããäŸåæ§æ³šå
¥ïŒDependsïŒãã»ãã¥ãªãã£ã¢ãžã¥ãŒã«ãé§äœ¿ããå
ç¢ãªèªèšŒæ©æ§ãæ§ç¯ããŠãããŸãã
ð ãã¹ã¯ãŒãã®ããã·ã¥å
ãŠãŒã¶ãŒãå
¥åãããã¹ã¯ãŒãã¯ããã®ãŸãŸä¿åããã«ããã·ã¥åããã®ãåºæ¬ã§ããããã¯ãäžãäžããŒã¿ããŒã¹ãæŒæŽ©ããå Žåã§ãããã¹ã¯ãŒãã®æŒæŽ©ãé²ãããã®å¿
é 察çã§ããPythonã§ã¯ passlib ã©ã€ãã©ãªãåºã䜿ãããç¹ã« bcrypt ã¢ã«ãŽãªãºã ã¯ä¿¡é Œæ§ãé«ãããšã§ç¥ãããŠããŸãã
pip install passlib[bcrypt]
以äžã¯ããã¹ã¯ãŒãã®ããã·ã¥åããã³ç §åãè¡ãããã®ãŠãŒãã£ãªãã£é¢æ°ã§ãïŒ
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
ãã®ããã«ãç»é²æã«ã¯ hash_password() ã䜿ãããã°ã€ã³æã«ã¯ verify_password() ã§ç
§åãè¡ããŸãã
ð§Ÿ OAuth2ã«ããããŒã¯ã³èªèšŒã®æºå
FastAPIã§ã¯ãã»ãã¥ã¢ãªããŒã¯ã³ããŒã¹èªèšŒãç°¡åã«æ§ç¯ã§ãããããOAuth2PasswordBearer ãçšããä»çµã¿ãæäŸãããŠããŸããããã¯BearerããŒã¯ã³ãããããŒããæœåºããèªèšŒåŠçãè¡ãããã®ã¢ãžã¥ãŒã«ã§ãã
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
async def get_current_token(token: str = Depends(oauth2_scheme)):
if token != "secrettoken123":
raise HTTPException(status_code=401, detail="Invalid token")
return token
ãã®é¢æ°ã¯ä¿è·ããããšã³ããã€ã³ãã§æ¬¡ã®ããã«äœ¿çšããŸãïŒ
@app.get("/secure-data")
async def secure_data(token: str = Depends(get_current_token)):
return {"message": "ãã®ããŒã¿ã¯ä¿è·ãããŠããŸãã"}
ãã®æ§é ãå¿çšããã°ããã°ã€ã³ããŠãããŠãŒã¶ãŒã®ã¿ãã¢ã¯ã»ã¹ã§ããã³ã³ãã³ãã容æã«å®è£ ã§ããŸãã
ð ããŒã¯ã³ãçºè¡ãããšã³ããã€ã³ã
ããŒã¯ã³ããŒã¹ã®èªèšŒãè¡ãã«ã¯ãã¯ã©ã€ã¢ã³ãã«ã¢ã¯ã»ã¹ããŒã¯ã³ãçºè¡ãã /token ãšã³ããã€ã³ããå¿
èŠã§ãããã®ãšã³ããã€ã³ãã§ã¯ããŠãŒã¶ãŒåãšãã¹ã¯ãŒããåãåããæ€èšŒåŸã«ã¢ã¯ã»ã¹ããŒã¯ã³ãè¿ããŸãã
from fastapi.security import OAuth2PasswordRequestForm
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
username = form_data.username
password = form_data.password
# å®éã«ã¯ããŒã¿ããŒã¹ã§ãŠãŒã¶ãŒæ
å ±ã確èªãããã¹ã¯ãŒãã®ç
§åãè¡ã
if username == "user1" and password == "secret":
return {"access_token": "secrettoken123", "token_type": "bearer"}
raise HTTPException(status_code=400, detail="ãŠãŒã¶ãŒåããã¹ã¯ãŒããéããŸã")
ãã® /token ã«POSTã§ username ãš password ãéä¿¡ãããšãããŒã¯ã³ãè¿ããããããçšããŠèªèšŒãããAPIãžã®ã¢ã¯ã»ã¹ãå¯èœã«ãªããŸãã
ð ããŒã¯ã³ã䜿ã£ãŠä¿è·ãããAPIã«ã¢ã¯ã»ã¹
Swagger UIã§ã¯ããšã³ããã€ã³ãå³äžã®ãAuthorizeããã¿ã³ãã¯ãªãã¯ããããšã§ããŒã¯ã³ãå
¥åã§ããŸããããŒã¯ã³ãèªèšŒããããšãä¿è·ããããšã³ããã€ã³ããžã®ã¢ã¯ã»ã¹ãèš±å¯ãããŸãã
ãã®ã€ã³ã¿ãŒãã§ãŒã¹ã«ãããéçºè
ããã¹ã¿ãŒã¯æè»œã«èªèšŒãããŒãäœéšããAPIã®åäœç¢ºèªãè¡ããŸããã¢ã¯ã»ã¹ããŒã¯ã³ãæéä»ãã®å Žåã¯ã宿çã«ããŒã¯ã³ãæŽæ°ããåŠçãå ãããšããå
ç¢ãªã·ã¹ãã ã«ãªããŸãã
ð§ ä»åŸã®å¿çšïŒJWTãèªå¯ã¬ãã«ã®ç®¡ç
ããå®çšçãªã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã¢ã¯ã»ã¹ããŒã¯ã³ãšããŠãJSON Web TokenïŒJWTïŒããå©çšããã®ãäžè¬çã§ããJWTã¯ãã€ããŒãå
ã«ãŠãŒã¶ãŒæ
å ±ãæå¹æéãå«ããããšãã§ãããµãŒããŒåŽã§ç¶æ
ãæããã«èªèšŒãè¡ãããããã¹ã±ãŒã©ãã«ãªèšèšã«é©ããŠããŸãã
ããã«ããŠãŒã¶ãŒããšã«ããŒã«ïŒadminãuserãguest ãªã©ïŒãå²ãåœãŠãŠã¢ã¯ã»ã¹æš©ãå¶åŸ¡ãããããŒã«ããŒã¹èªå¯ããããªãã¬ãã·ã¥ããŒã¯ã³ã䜿ã£ãŠé·æçãªã»ãã·ã§ã³ãç¶æããä»çµã¿ãªã©ããããŸãã
FastAPIã§ã¯ãPyJWT ã Authlib ãçµã¿åãããããšã§ãããããé«åºŠãªèªèšŒèšèšãè¡ãããšãã§ããŸãããããã®å®è£
ãçè§£ããããšã§ãæ¬æ ŒçãªWebãµãŒãã¹éçºã«ã察å¿å¯èœã§ãã
ð¯ ãŸãšã
- FastAPIã¯ãOAuth2ã«åºã¥ããå ç¢ãªèªèšŒã»èªå¯æ©èœãã·ã³ãã«ã«å®è£ ã§ãã匷åãªãã¬ãŒã ã¯ãŒã¯ã§ãã
- ãã¹ã¯ãŒãã¯çµ¶å¯Ÿã«å¹³æã§ä¿åããã
passlibã䜿ã£ãŠå®å šã«ããã·ã¥åããŸãããã - ããŒã¯ã³ã䜿ã£ãèªèšŒã¯ãã¢ãã€ã«ã¢ããªãããã³ããšã³ãSPAãšçžæ§ãè¯ããæ¡åŒµæ§ã«ãåªããŠããŸãã
- å®çšçãªå¿çšãšããŠãJWTãããŒã«ããŒã¹èªå¯ããªãã¬ãã·ã¥ããŒã¯ã³ã«ããã»ãã·ã§ã³ç¶æãªã©ãèŠéã«å ¥ããŠèšèšããŸãããã
以äžã§ãFastAPIã®ãåæ©ãã·ãªãŒãºã¯å®çµã§ãã
ð æåŸãŸã§èªãã§ããã ããããããšãããããŸããïŒ
ä»åŸã¯ãFastAPIãšVueãReactãçµã¿åãããSPAæ§æãDockerã䜿ã£ãAPIã®ãããã€ãFastAPIïŒSQLAlchemyã«ããæ¬æ Œçãªããã¯ãšã³ãéçºãªã©ã«ããã£ã¬ã³ãžããŠã¿ãŠãã ããã
æ ªåŒäŒç€ŸONE WEDGE
ãServerlessã§äžã®äžããã£ãšæ¥œããã ONE WEDGEã¯Serverlessã·ã¹ãã éçºãäžæ žæè¡ãšããŠWebç³»ã·ã¹ãã éçºãAWS/GCPãå©çšããæ¥åã·ã¹ãã ã»ãµãŒãã¹éçºãPWAãçšããã¢ãã€ã«éçºãAlexaã¹ãã«éçºãªã©ãå æ°ãšæè¡åãæŠåšã«ã客æ§ã«çæ¯ã«åãåã䟡å€åµé äŒæ¥ã§ãã
Discussion