FastAPI에서 Refresh Token 생성하는 구조
토요일.
지금만들고 있는 Toy Project는 Admin Site이기 때문에, 불특정 다수를 대상으로 하는 것도 아니고 통상적인 자그마한 수준의 트랜잭션을 감당 할 예정이라 모든 요청에 인증 및 권한체크를 하는 것으로 구상을 하고 있다.
인증 후 Token의 만료시간을 30분으로 잡고 있는데, 이 경우 계속 사용을 하면(===요청을 하면), 그 만료시간을 자동으로 늘려주려주는 방식의 구조를 만들려고 한다.
알아야 하는 사항
- login을 제외한 모든 요청은 인증체크와 권한체크가 되어야 한다는 전제이다.
- 모든 요청에 인증체크가 자동으로 되기 위해서 주입(injection)을 사용한다.
- 체크를 위한 값과 체크의 결과를 응답에 섞어서 받거나 내릴수 없기 때문에 request.header와 response.header를 사용한다.
- 해당 Request, Response 객체는 fastapi가 아니고 starlette에 있다.
- dependencies 선언에 파라메터를 넣을 수 없어서, 중간 함수가 하나 필요하다.
이 정도만 있으면, 구글링을 통해서 자신이 원하는 구조를 만들 수 있겠으나 코드를 좀 살펴보면.
from pydantic import BaseModel
from fastapi import APIRouter, Depends
from starlette.requests import Request
from starlette.responses import Response
# (1)
def check_auth_pass_response(request: Request, response: Response):
check_auth_by_header(request, response)
# (2)
routerDependencies = APIRouter(
prefix="/auth",
tags=["auth"],
dependencies=[Depends(check_auth_pass_response)]
)
# (3)
@routerDependencies.get("/checkAuth")
def check_for_autorization_and_authentication():
return None
(1)은 (2)에 의해서 선언된 Depends이다. (3)에서 바로 (1)로 갈 수도 있겠으나, 우리는 Request, Response 파라메터가 필요하기 때문에 중간 함수가 하나 필요하다.
(2)의 tags는 FastAPI docs에서 보이는 라우팅 경로들을 구분해주는 tag이고, perfix는 말 그대로 접두사니, 실제 호출은 /auth/checkAuth
가 된다.
(3)이 실제 표출되는 라우팅인데, 함수 상단에 @routerDependencies.
이라고 붙어있으니, (2)에 영향을 받는다는 것을 알 수 있다. 그리고 응답값이 None인데, 실제 Refresh Token은 생성해서 response.header에 달아 줄 것이라, Body는 필요로 하지 않는다.
왜 이런 구조가 되냐하면, 나중에 실제 응답 Body가 필요한 다른 요청에서도 저 주입[Depends(check_auth_pass_response)]을 동일하게 사용 할 수 있어야 하기 때문이다.
이것은 200이 아니면 모든 응답이 그 상황에 따라 매우 적절하게 Http Status Code로 보내줘야 한다는 것을 의미한다.
def check_auth_by_header(request: Request, response: Response):
# request.header에서 토큰을 꺼내서 검증하다가 뭔가 마음에 안들면 여기서 Http Exception을 raise하면 된다.
refresh_token = '' # 갱신된 Token을 넣어준다.
response.headers.setdefault('refreshtoken', refresh_token)
return None
‘refreshtoken’이라는 Key는 나중에 Client에서 Response.header에서 확인 할 수 있는 Key이고, Client는 적당한 부분에서 Client Token을 갱신 해 주면 되겠다.
주의 Axios에서는 Header가 모두 소문자로 바뀌는 현상이 있었다.
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["refreshtoken"]
)
여기까지만 하고, 브라우져 개발자 Network Tab에서 헤더가 찍히는것을 보고 코드에서 값에 접근 할 수 있다면 좋았겠지만.. 아니다.
Access-Control-Expose-Headers
라는것이 있는데, 요약하면 서버에서 보내 줄 때 별다른 표시를 안해주면, 브라우져가 알아서 잡다한것은 빼고 꼭 필요한 것만 전달해준다. 보안을 위한 브라우져의 양심이랄까?
FastAPI를 사용한다면 Fast CORS
부분을 보고 설정하면 되고, Node등 다른 것이라면 구글링을 해서 설정하면 된다.
Enjoy Reading This Article?
Here are some more articles you might like to read next: