32. Security - First Steps
1. Security - First Steps
- 일부 도메인에 백엔드 API가 있고, 다른 도메인이나 동일한 도메인의 다른 path에 프론트엔드가 있으며, 사용자 이름과 비밀번호를 사용하여 프론트엔드가 백엔드로 인증을 받을 수 있도록 하는 예제를 살펴보자.
- OAuth2를 사용하여 FastAPI로 빌드할 수 있으며, 필요한 정보를 찾기 위해 긴 사양 전체를 읽는 시간을 절약할 수 있게 된다.
- FastAPI에서 제공하는 도구를 사용하여 보안을 처리해 보자.
2. Create main.py
- 다음과 같이
main.py
를 작성한다.
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
3. Run it
- 다음과 같이 실행한다.
4. Check it
http://127.0.0.1:8000/docs
로 이동하면 다음과 같이 확인된다.
- Authorize 버튼을 클릭하면 다음과 같이
username
과password
등을 입력할 수 있는 인증 양식을 확인할 수 있다.
- 물론 최종 사용자를 위한 프론트엔드는 아니지만, 모든 API를 대화식으로 문서화하는 자동 도구이다.
- 프론트엔드 팀에서 사용할 수 있으며, 동일한 응용 프로그램을 디버그, 확인 및 테스트하기 위해 직접 사용할 수도 있다.
5. The password
flow
password
"flow"는 보안 및 인증을 처리하기 위해 OAuth2에서 정의된 "flows" 중 하나이다.- OAuth2는 백엔드 또는 API가 사용자를 인증하는 서버와 독립적일 수 있도록 설계되었다.
- 물론 위의 예제에서는 동일한 FastAPI 애플리케이션이 API와 인증을 같이 처리한다.
- 위의 예제를 다음과 같이 검토해 보자.
1] 사용자는 프론트엔드에 username
과 password
를 입력하고 Enter
를 누른다.
2] 프론트엔드는 해당 username
과 password
를 tokenUrl="token"
으로 선언된 API의 특정 URL로 보낸다.
3] 아직 구현하지는 않았지만 API는 username
과 password
를 확인하고 "token"으로 응답한다.
- "token"은 나중에 이 사용자를 확인하는 데 사용할 수 있는 일부 콘텐츠가 포함된 문자열이다.
- 일반적으로 token은 일정 시간이 지나면 만료되도록 설정된다.
- 따라서 사용자는 나중에 다시 로그인해야 한다.
- 그러므로 영원히 작동하는 영구키와 다르게 token을 도난당하는 것이 더 낫다.
4] 프론트엔드는 해당 token을 임시로 어딘가에 저장한다.
5] 사용자가 프론트엔드를 클릭하여 프론트엔드 웹 앱의 다른 섹션으로 이동한다.
6] 프론트엔드는 API에서 더 많은 데이터를 가져와야 한다.
- 그러나 특정 endpoint에 대한 인증이 필요하다.
- 따라서 API로 인증하기 위해
Bearer
값에 token을 더한Authorization
header를 보낸다. - token에
foobar
가 포함된 경우Authorization
header의 내용은Bearer foobar
가 된다.
6. FastAPI's OAuth2PasswordBearer
- FastAPI는 보안 기능을 구현하기 위해 다양한 추상화 수준에서 여러 도구를 제공한다.
- 이 예제에서는 Bearer token을 사용하여 Password flow와 함께 OAuth2를 사용할 것이며,
OAuth2PasswordBearer
클래스를 사용하여 이를 수행한다.
Note
- "bearer" token만 사용할 수 있는 것은 아니다.
- 예제에 가장 적합하기 때문에 사용하는 것이다.
- 다음과 같이
OAuth2PasswordBearer
클래스의 인스턴스를 생성할 때tokenUrl
매개변수를 전달하며, 이 매개변수에는 클라이언트가 token을 얻기 위해username
및password
를 보내는 데 사용할 URL이 포함된다.
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
Note
- 위의 예제의
tokenUrl="token"
은 아직 생성하지 않은 relative URLtoken
을 나타낸다. - relative URL이므로
./token
과 동일하다고 볼 수 있다. - 만약 API가
https://example.com/
에 있는 경우 realtive URL을 사용하기 때문에https://example.com/token
을 참조한다. - 하지만 API가
https://example.com/api/v1/
에 있는 경우https://example.com/api/v1/token
을 참조한다.
- 이 매개변수는 endpoint / path operation을 생성하지 않지만, URL
/token
이 클라이언트로 하여금 token을 가져오는 데 사용해야 하는 URL이 될 것이라고 선언한다. - 해당 정보는 OpenAPI에서 사용된 후 대화형 API 문서 시스템에서 사용된다.
- 위의 예제에서
oauth2_scheme
변수는OAuth2PasswordBearer
의 인스턴스이지만, "callable"이기도 하기 때문에Depends
를 사용할 수 있다.
7. Use it
Depends
를 사용하여 dependencyoauth2_scheme
을 전달할 수 있다.
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
- 이 dependency는 path operation function의 매개변수
token
에 할당된str
타입을 제공한다. - 그 후 FastAPI는 이 dependency를 사용하여 OpenAPI 스키마에서 "security scheme"을 정의할 수 있음을 알게 된다.
8. What it does
- 해당
Authorization
header에 대한 request를 살펴보고 값이Bearer
token인지 확인하고 token을str
타입으로 반환한다. - 만약
Authorization
header가 표시되지 않거나 값에Bearer
token이 없으면, 401 상태 코드 에러(UNAUTHORIZED
)로 응답한다.