본문으로 바로가기
728x90
반응형

 

Jwt 인증 시 header에 "access-token"이라는 key를 통해
특정 api 호출 시에만 검증 하고 싶다.

 

목차


    개요 

    FastAPI의 EndPoint에 Jwt Authenticate를 적용해야하는 상황이다.

     

    header key에는 "access-token"을 지정하고 EndPoint는 실제로 Authenticate를 수행할 건지 말 건지는 선택적으로 적용하고 싶었는데 어째선지 FastAPI에서는 관련 내용을 찾아보기 힘들었다. 

     

    문서에 관련 내용은 없어도 FastAPI에서 제공하는 APIRouter는 dependencies라는 parameter를 통해 API가 실행되기 전 수행할 동작을 지정할 수 있지만 다소 문제가 있다.

     

    Swagger 문서를 통해 해당 API가 실제로 Authenticate를 요구하는지 여부를 알 수가 없다는 점이다.

     

    이러한 문제를 어떻게 해결할 수 있을까?

     

     

    1.  기존 구현방식

    개요에서 언급했던 기존 구현 방식인 dependencies를 이용한 방식을 살펴보자. FastAPI의 APIRouter의 get, put, post, delete 등등 http method와 관련 있는 동작을 구현한 메서드에는 dependencies라는 argument가 존재한다.

     

    이를 이용하면 다음과 같은 코드를 작성해 특정 api가 실행되기 전 수행할 함수를 지정할 수 있다. 

    from fastapi import APIRouter, Depends
    
    test_router = APIRouter(tags=[''], prefix="")
    
    def verify_header():
        return ""
    
    @test_router.get(path="", dependencies=[Depands(verify_header)])
    def some_method():
        return "Ok"

    위 예제에서는 return 되는 값을 이용할 순 없다. 그러나 return 값이 필요하다면 dependencies가 아닌 다음과 같이 사용할 수 있다.

    def verify_header(acces_token: str = Header()):
        return acces_token
    
    
    @test_router.get(path="")
    def some_method(header=Depends(verify_header)):
        return "Ok"

     

     

     

    2.  기존 구현 방식의 문제

    앞서 언급했던 구현 방식의 문제점을 살펴보자. 우선 다음과 같이 선언된 케이스이다.

    @test_router.get(path="", dependencies=[Depands(verify_header)])

    너무 간결한 코드이기에  코드 그 자체의 문제점이 존재한다기보다는 이는 Swagger 문서 생성 방식에 문제가 있다.

    기존 구현 방식을 통해 성성된 Swagger 문서

    access_token이 parameters 입력 부분에 잘 생성된 것처럼 보이지만 이는 Swagger 문서를 통해 사용할 수 있는 Authroize 표시가 나타나지 않다는 점이 문제인 부분이다.

    API가 증가할수록 위와 같이 Swagger 문서도 생성될 것인데 어떤 API가 Authenticate를 요구하는지 눈에 들어오지 않는다.

     

    이 문제점은 앞서 언급한 다음과 같은 코드도 동일한 증상을 보여준다.

    @test_router.get(path="", dependencies=[Depends(verify_header)])
    def some_method(header=Depends(verify_header)):
        return "Ok"

     

     

    3. security 패키지에서는 방법을 찾지 못했다.

    Swagger 문서에 Authorize를 표시하기 위해 secutity에 관련된 FastAPI 내부에서 사용할 수 있는 객체들은 다음과 같다.

    from .api_key import APIKeyCookie as APIKeyCookie
    from .api_key import APIKeyHeader as APIKeyHeader
    from .api_key import APIKeyQuery as APIKeyQuery
    from .http import HTTPAuthorizationCredentials as HTTPAuthorizationCredentials
    from .http import HTTPBasic as HTTPBasic
    from .http import HTTPBasicCredentials as HTTPBasicCredentials
    from .http import HTTPBearer as HTTPBearer
    from .http import HTTPDigest as HTTPDigest
    from .oauth2 import OAuth2 as OAuth2
    from .oauth2 import OAuth2AuthorizationCodeBearer as OAuth2AuthorizationCodeBearer
    from .oauth2 import OAuth2PasswordBearer as OAuth2PasswordBearer
    from .oauth2 import OAuth2PasswordRequestForm as OAuth2PasswordRequestForm
    from .oauth2 import OAuth2PasswordRequestFormStrict as OAuth2PasswordRequestFormStrict
    from .oauth2 import SecurityScopes as SecurityScopes
    from .open_id_connect_url import OpenIdConnect as OpenIdConnect

    이 중 어느 항목들은 객체가 아니지만 "개요"에서 언급한 문제를 해결하기엔 가져다 사용할 수 있는 객체가 없다. 사실 안될 거야 없긴 하다. 이 객체들을 가져다 잘 분석하고 커스텀해서 사용한다면 어느 정도 가능하겠지만 배보다 배꼽이 더 크다.

     

     

    4. Security와 APIKeyHeader 이용하기

    계속 검색해 본 결과 "개요"에서 언급한 문제를 해결할 수 있는 방법을 찾을 수 있었다. 

    from fastapi import Security
    from fastapi.security import APIKeyHeader

    위 두 가지 도구를 이용하면 다음과 같은 코드를 작성할 수 있다.

    def verify_header(access_token=Security(APIKeyHeader(name='access-token')) ):
        return access_token
        
    @test_router.get(path="", dependencies=[verify_header()])
    def some_method():
        return "Ok"

     

    이제 Swagger 문서는 다음과 같이 변경된다.

     

    Swagger 문서에서 특정 EndPoint에 인증이 필요하다는 마크가 생겼다. 또한 API의 Key Header를 지정할 수 있는 버튼도 같이 생겨 다음과 같이 api를 호출하기 전 미리 header에 access-token을 설정할 수 있게 만든다.

     

     

    5. 마치며

    Jwt 인증은 많이 사용하는 편이기도 하니 기록한 내용처럼 이용할 수 있는 걸 참고해 두자.

     


     

    728x90
    반응형