Co-authored-by: tokusumi <41147016+tokusumi@users.noreply.github.com> Co-authored-by: Sho Nakamura <sh0nk.developer@gmail.com>
14 KiB
ãã¹ã¯ãŒãïŒããã³ããã·ã¥åïŒã«ããOAuth2ãJWTããŒã¯ã³ã«ããBearer
ããã§ã»ãã¥ãªãã£ã®æµããå šãŠããã£ãã®ã§ãJWTããŒã¯ã³ãšå®å šãªãã¹ã¯ãŒãã®ããã·ã¥åã䜿çšããŠãå®éã«ã¢ããªã±ãŒã·ã§ã³ãå®å šã«ããŠã¿ãŸãããã
ãã®ã³ãŒãã¯ãã¢ããªã±ãŒã·ã§ã³ã§å®éã«äœ¿çšãããããã¹ã¯ãŒãããã·ã¥ãããŒã¿ããŒã¹ã«ä¿åãããšãã£ãçšéã«å©çšã§ããŸãã
æ¬ç« ã§ã¯ãåç« ã®ç¶ãããå§ããŠãã³ãŒããã¢ããããŒãããŠãããŸãã
JWT ã«ã€ããŠ
JWTãšã¯ãJSON Web Tokensãã®ç¥ç§°ã§ãã
JSONãªããžã§ã¯ããã¹ããŒã¹ã®ãªãé·ãå¯éããæååã§è¡šçŸããããŒã¯ã³ã®ä»æ§ã§ããäŸãã°æ¬¡ã®ããã«ãªããŸãïŒ
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
ãããã¯æå·åãããŠããªãã®ã§ã誰ã§ãã³ã³ãã³ãããæ å ±ã埩å ã§ããŠããŸããŸãã
ããããããŒã¯ã³ã¯çœ²åãããŠãããããããªããçºè¡ããããŒã¯ã³ãåãåã£ã人ã¯ãããªããå®éã«çºè¡ãããšããããšãæ€èšŒã§ããŸãã
äŸãã°ã1é±éã®æå¹æéãæã€ããŒã¯ã³ãäœæãããšããŸãããŠãŒã¶ãŒãç¿æ¥ãã®ããŒã¯ã³ãæã£ãŠæ»ã£ãŠãããšãããã®ãŠãŒã¶ãŒã¯ãŸã ã·ã¹ãã ã«ãã°ã€ã³ããŠããããšãããããŸãã
1é±éåŸãããŒã¯ã³ãæéåããšãªããšã©ããªãã§ããããïŒãŠãŒã¶ãŒã¯èªå¯ããããæ°ããããŒã¯ã³ãåŸãããã«åã³ãµã€ã³ã€ã³ããªããã°ãªããŸããããŸãããŠãŒã¶ãŒïŒãŸãã¯ç¬¬äžè ïŒãããŒã¯ã³ãä¿®æ£ããŠæå¹æéã倿Žããããšããå Žåã眲åãäžèŽããªããããããŒã¯ã³ã®ä¿®æ£ãæ€ç¥ã§ããŸãã
JWT ããŒã¯ã³ã䜿ã£ãŠéãã§ã¿ãããšããæ¹ã¯ãhttps://jwt.io ããã§ãã¯ããŠãã ããã
python-jose ã®ã€ã³ã¹ããŒã«
Pythonã§JWTããŒã¯ã³ã®çæãšæ€èšŒãè¡ãããã«ãpython-joseãã€ã³ã¹ããŒã«ããå¿
èŠããããŸãïŒ
$ pip install python-jose[cryptography]
---> 100%
ãŸããPython-joseã ãã§ã¯ãªããæå·ãæ±ãããã®ããã±ãŒãžã远å ã§å¿ èŠãšããŸãã
ããã§ã¯ãæšå¥šãããŠãããã®ã䜿çšããŸãïŒpyca/cryptographyã
!!! tip "è±ç¥è" ãã®ãã¥ãŒããªã¢ã«ã§ã¯ä»¥åãPyJWTã䜿çšããŠããŸããã
ããããPython-joseã¯ãPyJWTã®ãã¹ãŠã®æ©èœã«å ããŠãåŸã«ä»ã®ããŒã«ãšçµ±åããŠæ§ç¯ããéã«ããããå¿
èŠãšãªãå¯èœæ§ã®ããããã€ãã®è¿œå æ©èœãæäŸããŠããŸãããã®ããã代ããã«Python-joseã䜿çšããããã«æŽæ°ãããŸããã
ãã¹ã¯ãŒãã®ããã·ã¥å
ãããã·ã¥åããšã¯ãããã³ã³ãã³ãïŒããã§ã¯ãã¹ã¯ãŒãïŒããèŠåæ§ã®ãªããã€ãåïŒåãªãæååïŒã«å€æããããšã§ãã
ç¹åŸŽãšããŠãå šãåãå 容ïŒå šãåããã¹ã¯ãŒãïŒãæž¡ããšãå šãåãèŠåæ§ã®ãªããã€ãåã«å€æãããŸãã
ããããèŠåæ§ã®ãªããã€ãåããå ã®ãã¹ã¯ãŒãã«æ»ãããšã¯ã§ããŸããã
ãã¹ã¯ãŒãã®ããã·ã¥åã䜿ãçç±
ããŒã¿ããŒã¹ãçãŸããŠãããŠãŒã¶ãŒã®å¹³æã®ãã¹ã¯ãŒãã¯çãŸãããããã·ã¥å€ã ããçãŸããŸãã
ãããã£ãŠãæ³¥æ£ã¯ãã®ãã¹ã¯ãŒããå¥ã®ã·ã¹ãã ã§äœ¿ããŸããïŒå€ãã®ãŠãŒã¶ãŒã¯ã©ãã§ãåããã¹ã¯ãŒãã䜿çšããŠãããããå±éºæ§ããããŸãïŒã
passlib ã®ã€ã³ã¹ããŒã«
PassLib ã¯ããã¹ã¯ãŒãã®ããã·ã¥ãåŠçããããã®åªããPythonããã±ãŒãžã§ãã
ãã®ããã±ãŒãžã¯ãå€ãã®å®å šãªããã·ã¥ã¢ã«ãŽãªãºã ãšãŠãŒãã£ãªãã£ããµããŒãããŸãã
æšå¥šãããã¢ã«ãŽãªãºã ã¯ãBcryptãã§ãã
ãã®ãããBcryptãæå®ããŠPassLibãã€ã³ã¹ããŒã«ããŸãïŒ
$ pip install passlib[bcrypt]
---> 100%
!!! tip "è±ç¥è"
passlibã䜿çšãããšãDjangoãFlaskã®ã»ãã¥ãªãã£ãã©ã°ã€ã³ãªã©ã§äœæããããã¹ã¯ãŒããèªã¿åããããã«èšå®ã§ããŸãã
äŸãã°ãDjangoã¢ããªã±ãŒã·ã§ã³ããããŒã¿ããŒã¹å
ã®åãããŒã¿ãFastAPIã¢ããªã±ãŒã·ã§ã³ãšå
±æã§ããã ãã§ã¯ãªããåãããŒã¿ããŒã¹ã䜿çšããŠDjangoã¢ããªã±ãŒã·ã§ã³ãåŸã
ã«ç§»è¡ããããšãã§ããŸãã
ãŸãããŠãŒã¶ãŒã¯Djangoã¢ããªãŸãã¯**FastAPI**ã¢ããªããããåæã«ãã°ã€ã³ã§ããããã«ãªããŸãã
ãã¹ã¯ãŒãã®ããã·ã¥åãšæ€èšŒ
å¿
èŠãªããŒã«ã passlibããã€ã³ããŒãããŸãã
PassLib ã®ãcontextããäœæããŸããããã¯ããã¹ã¯ãŒãã®ããã·ã¥åãšæ€èšŒã«äœ¿çšããããã®ã§ãã
!!! tip "è±ç¥è" PassLibã®contextã«ã¯ãæ€èšŒã ããèš±ãããéæšå¥šã®å€ãããã·ã¥ã¢ã«ãŽãªãºã ãå«ããæ§ã ãªããã·ã¥ã¢ã«ãŽãªãºã ã䜿çšããæ€èšŒæ©èœããããŸãã
äŸãã°ããã®æ©èœã䜿çšããŠãå¥ã®ã·ã¹ãã ïŒDjangoãªã©ïŒã«ãã£ãŠçæããããã¹ã¯ãŒããèªã¿åã£ãŠæ€èšŒããBcryptãªã©ã®å¥ã®ã¢ã«ãŽãªãºã ã䜿çšããŠæ°ãããã¹ã¯ãŒããããã·ã¥ãããšãã£ãããšãã§ããŸãã
ãããŠãåæã«ãããã¯ãã¹ãŠã«äºææ§ããããŸãã
ãŠãŒã¶ãŒããéãããŠãããã¹ã¯ãŒããããã·ã¥åãããŠãŒãã£ãªãã£ãŒé¢æ°ãäœæããŸãã
ãŸããåãåã£ããã¹ã¯ãŒããä¿åãããŠããããã·ã¥ãšäžèŽãããã©ãããæ€èšŒãããŠãŒãã£ãªãã£ãäœæããŸãã
ããã«ããŠãŒã¶ãŒãèªèšŒããŠè¿ã颿°ãäœæããŸãã
{!../../../docs_src/security/tutorial004.py!}
!!! note "åè"
æ°ããïŒåœã®ïŒããŒã¿ããŒã¹fake_users_dbã確èªãããšãããã·ã¥åããããã¹ã¯ãŒããæ¬¡ã®ããã«ãªã£ãŠããããšãããããŸãïŒ"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"
JWTããŒã¯ã³ã®åãæ±ã
ã€ã³ã¹ããŒã«ããè€æ°ã®ã¢ãžã¥ãŒã«ãã€ã³ããŒãããŸãã
JWTããŒã¯ã³ã®çœ²åã«äœ¿çšãããã©ã³ãã ãªç§å¯éµãçæããŸãã
å®å šãªã©ã³ãã ç§å¯éµãçæããã«ã¯ã次ã®ã³ãã³ãã䜿çšããŸãïŒ
$ openssl rand -hex 32
09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7
ãããŠãåºåãããæååã倿°SECRET_KEYã«ã³ããŒããŸããïŒäŸã«èšèŒããŠããç§å¯éµã¯å®éã«äœ¿çšããªãã§ãã ããïŒ
JWTããŒã¯ã³ã®çœ²åã«äœ¿çšããã¢ã«ãŽãªãºã "HS256"ãæå®ãã倿°ALGORITHMãäœæããŸãã
ããŒã¯ã³ã®æå¹æéãæå®ãã倿°ACCESS_TOKEN_EXPIRE_MINUTESãäœæããŸãã
ã¬ã¹ãã³ã¹ã®ããŒã¯ã³ãšã³ããã€ã³ãã§äœ¿çšããPydanticã¢ãã«ãå®çŸ©ããŸãã
æ°ããã¢ã¯ã»ã¹ããŒã¯ã³ãçæãããŠãŒãã£ãªãã£é¢æ°ãäœæããŸãã
{!../../../docs_src/security/tutorial004.py!}
äŸåé¢ä¿ã®æŽæ°
get_current_userãæŽæ°ããŠãå
ã»ã©ãšåãããŒã¯ã³ãåãåãããã«ããŸãããä»åã¯JWTããŒã¯ã³ã䜿çšããŸãã
åãåã£ãããŒã¯ã³ã埩å·ããŠæ€èšŒããçŸåšã®ãŠãŒã¶ãŒãè¿ããŸãã
ããŒã¯ã³ãç¡å¹ãªå Žåã¯ãããã«HTTPãšã©ãŒãè¿ããŸãã
{!../../../docs_src/security/tutorial004.py!}
/token ãã¹ãªãã¬ãŒã·ã§ã³ã®æŽæ°
ããŒã¯ã³ã®æå¹æéã衚ãtimedeltaãäœæããŸãã
JWTã¢ã¯ã»ã¹ããŒã¯ã³ãäœæãããããè¿ããŸãã
{!../../../docs_src/security/tutorial004.py!}
JWTã®"subject" sub ã«ã€ããŠã®æè¡çãªè©³çް
JWTã®ä»æ§ã§ã¯ãããŒã¯ã³ã®subjectã衚ãããŒsubããããšãããŠããŸãã
䜿çšãããã©ããã¯ä»»æã§ãããsubã¯ãŠãŒã¶ãŒã®è奿
å ±ãå
¥ããããã«èŠå®ãããŠããã®ã§ãããã§äœ¿çšããŸãã
JWTã¯ããŠãŒã¶ãŒãèå¥ããŠããã®ãŠãŒã¶ãŒãAPIäžã§çŽæ¥æäœãå®è¡ã§ããããã«ãã以å€ã«ããä»ã®çšéã§äœ¿çšãããããšããããŸãã
äŸãã°ããè»ãããããã°èšäºããèå¥ããããšãã§ããŸãã
ãããŠãããã©ã€ããïŒè»ã®å ŽåïŒããç·šéãïŒããã°ã®å ŽåïŒãªã©ããã®ãšã³ãã£ãã£ã«é¢ããæš©éã远å ã§ããŸãã
ãŸããJWTããŒã¯ã³ããŠãŒã¶ãŒïŒãŸãã¯ãããïŒã«æž¡ãããšãã§ããŸãããŠãŒã¶ãŒã¯ãJWTããŒã¯ã³ã䜿çšããã ãã§ãã¢ã«ãŠã³ããæã£ãŠããªããŠããAPIãçæããJWTããŒã¯ã³ã䜿ã£ãŠãããã®è¡åïŒè»ã®é転ãããã°æçš¿ã®ç·šéïŒãå®è¡ã§ããã®ã§ãã
ãããã®ã¢ã€ãã¢ã䜿çšãããšãJWTãããé«åºŠãªã·ããªãªã«äœ¿çšã§ããŸãã
ããããªããããããã®ãšã³ãã£ãã£ã®ããã€ããåãIDãæã€å¯èœæ§ããããŸããäŸãã°ãfooïŒãŠãŒã¶ãŒfooãè» fooãããã°æçš¿fooïŒãªã©ã§ãã
IDã®è¡çªãåé¿ããããã«ããŠãŒã¶ãŒã®JWTããŒã¯ã³ãäœæãããšããsubããŒã®å€ã«ãã¬ãã£ãã¯ã¹ãä»ããããšãã§ããŸãïŒäŸãã°ãusername:ïŒããããã£ãŠããã®äŸã§ã¯ãsubã®å€ã¯æ¬¡ã®ããã«ãªã£ãŠããå¯èœæ§ããããŸãïŒusername:johndoe
èŠããŠããã¹ãéèŠãªããšã¯ãsubããŒã¯ã¢ããªã±ãŒã·ã§ã³å
šäœã§äžæã®èå¥åãæã¡ãæååã§ããå¿
èŠããããšããããšã§ãã
確èª
ãµãŒããŒãå®è¡ããããã¥ã¡ã³ãã«ç§»åããŸãïŒhttp://127.0.0.1:8000/docs
次ã®ãããªãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ã衚瀺ãããŸãïŒ
ååãšåãæ¹æ³ã§ã¢ããªã±ãŒã·ã§ã³ã®èªå¯ãè¡ããŸãã
次ã®èªèšŒæ å ±ã䜿çšããŸãïŒ
Username: johndoe
Password: secret
!!! check "確èª"
ã³ãŒãã®ã©ãã«ãå¹³æã®ãã¹ã¯ãŒã"secret"ã¯ãªããããã·ã¥åããããã®ãããªãããšã確èªããŠãã ããã
ãšã³ããã€ã³ã/users/me/ãåŒã³åºããšã次ã®ãããªã¬ã¹ãã³ã¹ãåŸãããŸãïŒ
{
"username": "johndoe",
"email": "johndoe@example.com",
"full_name": "John Doe",
"disabled": false
}
éçºè ããŒã«ãéããšãéä¿¡ãããããŒã¿ã«ã¯ããŒã¯ã³ã ããå«ãŸããŠããããã¹ã¯ãŒãã¯ãŠãŒã¶ãŒãèªèšŒããŠã¢ã¯ã»ã¹ããŒã¯ã³ãååŸããæåã®ãªã¯ãšã¹ãã§ã®ã¿éä¿¡ããããã®åŸã¯éä¿¡ãããªãããšãããããŸãã
!!! note "åè"
ããããŒã®Authorizationã«ã¯ãBearerã§å§ãŸãå€ããããŸãã
scopes ã䜿ã£ãé«åºŠãªãŠãŒã¹ã±ãŒã¹
OAuth2ã«ã¯ããã¹ã³ãŒãããšããæŠå¿µããããŸãã
ããããå©çšããŠãJWTããŒã¯ã³ã«ç¹å®ã®æš©éã»ããã远å ããããšãã§ããŸãã
ãããŠããã®ããŒã¯ã³ããŠãŒã¶ãŒã«çŽæ¥ããŸãã¯ç¬¬äžè ã«äžããŠãå¶éä»ãã§APIãæäœã§ããŸãã
ãããã®äœ¿ç𿹿³ãFastAPIãžã®çµ±åæ¹æ³ã«ã€ããŠã¯ãé«åºŠãªãŠãŒã¶ãŒã¬ã€ãã§åŸã»ã©èª¬æããŸãã
ãŸãšã
ãããŸã§ã®èª¬æã§ãOAuth2ãJWTãªã©ã®èŠæ Œã䜿ã£ãå®å šãªFastAPIã¢ããªã±ãŒã·ã§ã³ãèšå®ããããšãã§ããŸãã
ã»ãšãã©ã®ãã¬ãŒã ã¯ãŒã¯ã«ãããŠãã»ãã¥ãªãã£ãæ±ãããšã¯éåžžã«è€éãªèª²é¡ãšãªããŸãã
ç°¡ç¥åããããããã±ãŒãžã®å€ãã¯ãããŒã¿ã¢ãã«ãããŒã¿ããŒã¹ãå©çšå¯èœãªæ©èœã«ã€ããŠå€ãã®åŠ¥åãããªããã°ãªããŸããããããŠãããŸãã«ãåçŽåãããããã±ãŒãžã®äžã«ã¯ãå®ã¯ã»ãã¥ãªãã£äžã®æ¬ é¥ããããã®ããããŸãã
FastAPIã¯ãã©ã®ãããªããŒã¿ããŒã¹ãããŒã¿ã¢ãã«ãããŒã«ã«å¯ŸããŠã劥åããããšã¯ãããŸããã
ãã®ããããããžã§ã¯ãã«åãããŠèªç±ã«éžæããããšãã§ããŸãã
ãŸããFastAPIã¯å€éšããã±ãŒãžãçµ±åããããã«è€éãªä»çµã¿ãå¿
èŠãšããªããããpasslibãpython-joseã®ãããªããæŽåããåºã䜿ãããŠããå€ãã®ããã±ãŒãžãçŽæ¥äœ¿çšããããšãã§ããŸãã
ããããæè»æ§ãå ç¢æ§ãã»ãã¥ãªãã£ãæãªãããšãªããå¯èœãªéãããã»ã¹ãç°¡çŽ åããããã®ããŒã«ãæäŸããŸãã
ãŸããOAuth2ã®ãããªå®å šã§æšæºçãªãããã³ã«ãæ¯èŒçç°¡åãªæ¹æ³ã§äœ¿çšã§ããã ãã§ã¯ãªããå®è£ ããããšãã§ããŸãã
OAuth2ã®ãã¹ã³ãŒããã䜿ã£ãŠãåãåºæºã§ãã现ããæš©éã·ã¹ãã ãå®çŸããæ¹æ³ã«ã€ããŠã¯ãé«åºŠãªãŠãŒã¶ãŒã¬ã€ãã§è©³ãã説æããŠããŸããã¹ã³ãŒãä»ãã®OAuth2ã¯ãFacebookãGoogleãGitHubãMicrosoftãTwitterãªã©ãå€ãã®å€§æèªèšŒãããã€ããããµãŒãããŒãã£ã®ã¢ããªã±ãŒã·ã§ã³ãšèªç€Ÿã®APIãšã®ããåãããŠãŒã¶ãŒã«ä»£ãã£ãŠèªå¯ããããã«äœ¿çšããŠããä»çµã¿ã§ãã