[FastAPI] 7. Google-auth ๋ฐ PyJWT๋ฅผ ์ด์ฉํ OAuth2 ์ธ์ฆ ๊ตฌํ 2
์ง๋ ๊ธ์ ์ด์ด์ ์ด๋ฒ ํฌ์คํธ์์๋ OAuth2 ์ธ์ฆ ํ ํฐ์ API์์ ๋ฐ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
HTTP Header
์ฐ๋ฆฌ๊ฐ REST API๋ฅผ ํต์ ํ๋ ๋ฐ ์ฌ์ฉํ๋ HTTP ํ๋กํ ์ฝ์ Header์ Body๋ผ๋ ๊ตฌ์กฐ๋ก ์ด๋ค์ ธ ์์ต๋๋ค. Header์ Body ๋ชจ๋ ๊ฐ๋ฐ์๊ฐ ๋ค๋ฃฐ ์ ์๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ก ๋์ด ์์ผ๋ฉฐ Header์๋ ์ ์กํ๊ณ ์ ํ๋ ์๋ฒ ํน์ ํด๋ผ์ด์ธํธ์ ์ ๋ณด ๋ด์ง ์ ์กํ๊ณ ์ ํ๋ ๋์์ ๋ถ๊ฐ์ ์ธ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋๊ฒจ์ค ๋ ์ฌ์ฉํฉ๋๋ค.
์ฌ์ด ์์๋ก ์์ ๊ฐ์ด ๋ก์ปฌ ์๋ฒ์๊ฒ GET ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ๋ฆฌ์์ค๋ฅผ ๊ฐ์ ธ์ค๋ ํธ์ถ์ ์ ๋ฌํ์ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ ๋์์์๊ฒ ๋ถ๊ฐ์ ์ธ ๋ฉํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋๋ก Key-value ํํ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
์ด ์ค์์ ๊ฐ์ฅ ๋ง์ด ๋ค์ด๊ฐ๋ Header ๊ฐ์๋ Content-type, Cache-Control ๋ฑ์ด ์๋๋ฐ, Content-type์ ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ ํน์ ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์๊ฒ ์ฃผ๋ ๋ฐ์ดํฐ์ ์ ํ, Cache-control์ REST์์ ์ง์ํ๋ ์บ์๋ฅผ ์ด๋ ์์ ๊น์ง ๋ณด๊ดํ๊ณ ๋ง๋ฃํ ๊ฒ์ธ์ง ๋ฑ์ ๋ํ ์ ๋ณด๊ฐ ๋ด๊ฒจ์ง๊ฒ ๋ฉ๋๋ค.
์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ํค๋์ ์ํธํ ๋ด์ง ์ธ์ฝ๋ฉ๋ JWT ํ ํฐ์ ๋ด์ ๊ฑด๋ฐ์. ์ ์ด๊ฒ์ body์ ๋ด์ง ์๊ณ , header์ ๋ด๋ ๊ฒ์ผ๊น์?
์ฐ๋ฆฌ๋ Header์ Body์ ๋ํ ๋ช ํํ ๊ตฌ๋ถ์ด ํ์ํ๋ฐ, body๋ ํด๋น ์๋น์ค์์ ๊ฐ์ ธ์ค๊ฑฐ๋ ๋ด๋ ๋ฆฌ์์ค๋ฅผ ๋ด์ ๋ ์ฌ์ฉํ๊ณ , Header๋ ์๋ฒ์ ์ ๋ณด๋ ์ธ์ฆ ์๋จ๊ณผ ๊ฐ์ ์๋น์ค์ ํ์ํ ๋ฆฌ์์ค ์ธ์ ํญ๋ชฉ์ ๋ด์ ๋ ์ฌ์ฉํ๊ธฐ๋ก ๊ตฌ๋ถ๋์ด์ก๊ธฐ ๋๋ฌธ์ธ๋ฐ์.
๋ฐ๋ผ์ ์๋ํฌ์ธํธ์ ๋ฆฌ์์ค๊ฐ ์ด๋ค ๊ฒ์ด ์ค์ฌ์ด๋์ ๋ฐ๋ผ ์ด ๋ฐ์ดํฐ๊ฐ Header์ ๋ค์ด๊ฐ๊ณ , Body์ ๋ค์ด๊ฐ๋์ง๋ ์๋น์ค ๊ฐ๋ฐ์๊ฐ ์ ํ ์ ์๋๋ฐ, ๋ณดํต์ ์ด๋ฐ์์ผ๋ก ๋๋๋ ๊ฒ์ด ํ๋ฒํ๋ค๊ณ ๋ณด์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.
Get Header in FastAPI
๊ทธ๋ ๋ค๋ฉด FastAPI์์ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญํ Header ๊ฐ์ ์ด๋ค์์ผ๋ก ๋ฐ์ ์ ์์๊น์?
์ผ๋ฐ์ ์ผ๋ก FastAPI์์ ํด๋ผ์ด์ธํธ์ ์์ฒญ๊ฐ์ ๋ฐ์ ๋๋ ์์ ์ฝ๋๋ก ๋ฐ์ ์ ์์ต๋๋ค. ๊ธฐ์กด์ pydantic๊ณผ ๊ฐ์ Schema validation์ ์ฌ์ฉํ์ ๋์๋ ์ฌ๋ญ ๋ค๋ฅธ ๋ชจ์ต์ด์ง๋ง ์ผ๋ฐ์ ์ผ๋ก๋ ์์ ๊ฐ์ด ๋ฐ์ผ๋ฉฐ Request ๊ฐ์ฒด๋ฅผ ํตํด์ header, cookie, path_params ๋ฑ์ ์ข ํฉ์ ์ผ๋ก ํ์ธํ ์ ์์ต๋๋ค.
๋ง์ฝ ํน์ Key์ ํด๋นํ๋ Header ๊ฐ๋ง์ ๋ฐ๊ณ ์ ํ๋ ๊ฒฝ์ฐ FastAPI์ ๋ชจ๋์์ Header ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ํน์ Key ๊ฐ์ ํด๋นํ๋ Header ๊ฐ์ ๋ฐ์์ฌ ์ ์์ต๋๋ค.
์ฐ๋ฆฌ๋ ์ฌ๊ธฐ์ Authorization ์ด๋ผ๋ Key๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ฉฐ ์ด์ชฝ์ JWT ํ ํฐ์ ๋ฃ์ด์ ๋ณด๋ด๋ฉด ์ด๋ฅผ decodeํด์ ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ฃผ๋ API๋ฅผ ๋ง๋ค์ด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
Decode Token
์ง๋ ํฌ์คํธ์์ ํ ํฐ์ ์ธ์ฝ๋ฉํ์ ๋ payload์ key๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ์ฌ์ฉํ์ฌ ํ ํฐ์ ์ํธํ ํ์๋๋ฐ์. ๊ทธ๋ฐ๋ฐ, ์ฌ๊ธฐ์๋ ์ฝ๊ฐ์ ํจ์ ์ด ์จ๊ฒจ์ ธ ์์ต๋๋ค.
encode๋ฅผ ํ์ ๋์ ๋ง์ฐฌ๊ฐ์ง๋ก decode์ key ๊ฐ๊ณผ ํ ํฐ ๊ฐ์ ์ฌ์ฉํ๊ฒ ๋๋ฉด decode ๋์ง ์๊ณ ์ค๋ฅ๊ฐ ๋ํ๋ฉ๋๋ค.
์ด ์ค๋ฅ๋ algorithms ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๋์ ์ถ๊ฐํ๋ผ๋ ๋ด์ฉ์ธ๋ฐ์. PyJWT 1.7.1 ๋ฒ์ ์ ์ฌ์ฉํ๋ค๋ฉด ์๋์ ์ฝ๋๋ฅผ ์ด์ฉํ์ฌ ์ด ๊ณผ์ ์ ๋ฌด์ํ ์๋ ์์ต๋๋ค.
๊ทธ๋ฌ๋ PyJWT 2.x ๋ฒ์ ์ด์์์๋ ์ ์ฝ๋๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ ๋ฐ๋์ algorithms๋ฅผ ์ง์ ํด์ค์ผ๋ง ํฉ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ฐ๋ฆฌ๋ ์ด๋ค ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ ๊ฒ์ผ๊น์?
encode ํจ์๋ฅผ ์กฐ๊ธ ์ดํด๋ณด๋ฉด ๊ธฐ๋ณธ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก HS256์ ์ฌ์ฉํ์์ ์ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ decode๋ฅผ ํ ๋ algorihtms์ HS256์ ๋ถ์ฌ์ฃผ๋ฉด decode๊ฐ ๋ฉ๋๋ค.
๋ง์ฝ ํ ํฐ์ ์ ๋ ฅ๋ฐ์ง ๋ชปํ ๊ฒฝ์ฐ 401 ์ค๋ฅ๋ฅผ ๋ฐํํ๋๋ก ํฉ๋๋ค.
Use DI
์ฌ๊ธฐ๊น์ง ์ธ์ฆ์ด ํ์ํ ๊ตฌ๊ฐ์ ๋ํด์ Authorization ํค๋์ ์๋ ํ ํฐ์ ๋ฐ๊ณ ์ด ํ ํฐ์ด ์ฃผ์ด์ง์ ๋ฐ๋ผ ๋ฐํํ๋ ๊ฐ์ ๋ฐ๊พธ๋๋ก ๊ตฌํํ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ, ์ธ์ฆ์ด ํ์ํ API ๊ตฌ๊ฐ๋ง๋ค ์ด๋ฌํ ์ฝ๋๋ฅผ ์ฐ๊ฒ ๋๋ค๋ฉด ์ค๋ณต ์ฝ๋๊ฐ ๋น๋ฒํ๊ฒ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ฌ๊ธฐ์ Middleware๋ฅผ ์ฌ์ฉํ์ฌ API ํธ์ถ ์ ํ๊ตฌ๊ฐ์ ์ธ์ฆ ์ ์ฐจ๋ฅผ ์ถ๊ฐํ์ฌ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ๊ทธ๋ ์ง๋ง ํ์์๋ API ๊ตฌ๊ฐ์์ ์ด๋ฅผ ์คํํ๋ ๊ฒ์ ๋ถํ์ํ ํธ์ถ์ ํด๋นํ๊ธฐ๋ ํฉ๋๋ค.
์ด๋ด ๋๋ FastAPI์ DI(Dependency Injection) ๊ธฐ๋ฒ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. FastAPI์์๋ ํจ์์ ํด๋์ค ๋ชจ๋์ ์์กด์ฑ ์ฃผ์ ์ ๊ฑธ์ ์ ์๋๋ฐ, ๊ฐ๋จํ ์ฌ์ฉ๋ฒ์ ์์๋ ์ด๋ฏธ SQLAlchemy๋ฅผ FastAPI์์ ์ ์ฉํ๋ ํฌ์คํธ์์ ๋ค๋ค๋ดค์ต๋๋ค.
๋ฐ๋ผ์ ์ด ๊ธฐ๋ฒ์ ๊ฐ์ง๊ณ ํ์ํ API ๊ตฌ๊ฐ์ Token ์ธ์ฆํ๋ ์์๋ฅผ ๋ฃ์ด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
ํด๋์ค ํธ์ถ์ Header์์ authorization ๊ฐ์ ๋ฐ๋๋ก ํฉ๋๋ค. ๋ง์ฝ ๊ฐ์ด ์๋ค๋ฉด 401 Unauthorized ์ค๋ฅ๋ฅผ ๋ฐํํฉ๋๋ค.
FastAPI์์ ์ ๊ณตํ๋ Depends ํจ์๋ฅผ ์ด์ฉํ์ฌ AuthProvider๋ฅผ ์ฃผ์ ํ๋ฉด API๊ฐ ํธ์ถ๋ ๋๋ง๋ค AuthProvider ํด๋์ค๋ฅผ ์์ฑํ๋๋ฐ, ์์์ ํด๋์ค ์์ฑ์ ํธ์ถ๋๋ __call__ ๋ฉ์๋๋ฅผ ์ด์ฉํ์ฌ authorization ๊ฐ์ ๋ฐํํ์ผ๋ฏ๋ก ์ด์ authorization ๊ฐ์ด ๋ฐํ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
Using DI with OAuth2Scheme
FastAPI์์๋ ์ด์ ๋น์ทํ ํํ๋ก OAuth2Scheme ํด๋์ค๋ฅผ ์ ๊ณตํ๊ณ ์์ต๋๋ค. Bearer ํ ํฐ ๊ธฐ๋ฐ์ OAuth2PasswordBearer์ ์ ๊ณตํ๋ฉฐ ์ฐ๋ฆฌ๋ Bearer ํ ํฐ ํฌ๋งทํํ๋ก JWT ํ ํฐ์ ์ธ์ฝ๋ฉ ํ์์ผ๋ฏ๋ก ์ด ํด๋์ค๋ฅผ ์ด์ฉํ์ฌ ์ข ๋ ์ฝ๊ฒ OAuth2 ๊ธฐ๋ฐ์ ์ธ์ฆ ์๋น์ค๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
์ฌ๊ธฐ์ tokenUrl ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๋๋ฐ, ์ด๊ฒ์ OAuthFlows์ ์ฌ์ฉํ์ฌ API ๋ฌธ์์์ Flow๋ฅผ ํ์ธํ๊ธฐ ์ํจ์ ๋๋ค. ๋ก๊ทธ์ธ URI๊ฐ ์๋ค๋ฉด ์ ๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด ์ ์ง ์์ผ์ ๋ ๋ฉ๋๋ค.
auto_error ํ๋ผ๋ฏธํฐ๋ ํ ํฐ์ด ๋น์ ์์ ์ด๊ฑฐ๋ ์ฃผ์ด์ง์ง ์์ ๊ฒฝ์ฐ ์๋์ผ๋ก ์ค๋ฅ ๋ฐํ์ ํ ๊ฒ์ธ์ง๋ฅผ ๋ฌป๋ ํ๋ผ๋ฏธํฐ์ธ๋ฐ, ๊ธฐ๋ณธ๊ฐ์ True ์ ๋๋ค.
์ด๋ฐ์์ผ๋ก ํ์ํ API ํฌ์ธํธ์ DI๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๊ฒ JWT ํ ํฐ์ ๋์ฝ๋ฉํ์ฌ ๊ถํ์ ํ์ธํ๊ณ ์ธ์ฆํ ์ ์์ต๋๋ค.
๋ง์น๋ฉฐ...
FastAPI๋ก OAuth2 ๋ก๊ทธ์ธ์ ์ด์ฉํ์ฌ ์ธ์ฆํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๊ฐ๋จํ ๋ค๋ค๋ดค์ต๋๋ค. Spring Security์ ๋น๊ตํ๋ฉด ๋ฌ๋ ์ปค๋ธ๋ ๊ทธ๋ค์ง ๋ง์ด ๊น์ง ์์ ๋๋์ ๋๋ค. ๊ทธ๋ฌ๋ JWT๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ์๊ณ , ์ด๋ฅผ ์ด๋ค์์ผ๋ก ๊ตฌํํ๋ ๊ฒ์ ๋ํด ์ต์ํด์ ธ ์์ด์ผ ํฉ๋๋ค.
๋ฐ๋๋ก Spring Security๋ JWT์ ๊ตฌ๋ ๋ฐฉ์ ๋ณด๋ค๋ Spring Security์ ๋ ์ด์ด๋ ์ฝ๋ฐฑ ํจ์ ๋ฑ์ ์๊ณ ์ด๋ฅผ ์ ์ ํ ์ด์ฉํ๋ ๋ฐฉ๋ฒ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ป๊ฒ ๋ณด๋ฉด ๋ฌ๋ ์ปค๋ธ๋ Spring Security๊ฐ ์ข ๋ ๋๋ค๊ณ ๋ณผ ์ ์์ ๊ฒ ๊ฐ๋ค์.