FastAPI — 타입이 곧 계약이다 · 토큰이 있어도 남의 문서는 읽을 수 없다 · 실습
토큰이 있어도 남의 문서는 읽을 수 없다
목표
인증·권한·소유권을 분리하고 같은 404로 리소스 존재를 숨깁니다.
왜 중요한가
로그인한 사용자가 주소의 문서 번호만 바꾸어 다른 팀의 문서를 읽었다. 토큰이 유효하다는 사실과 특정 문서를 읽을 권리는 별개다. 이 실습에서는 고정 토큰 사전을 사용해 인증 서버를 대신한다. 토큰을 발급하거나 JWT 서명을 구현하는 실습이 아니라, 인증 결과 이후의 권한 경계를 구현하는 실습이다.
단계
1. /root/work/fa-ownership-lab/service.py에서 bearer(header)는 정확히 'Bearer '로 시작하고 뒤에 공백 없는 토큰 하나가 있을 때 토큰을 반환합니다. None·빈 토큰·다른 scheme·추가 공백은 ValueError입니다.
처음 한 번 준비하세요. 기존 파일은 덮어쓰지 않습니다.
mkdir -p /root/work/fa-ownership-labtest -e /root/work/fa-ownership-lab/service.py || cp /opt/fixtures/ten_labs/fa-ownership-lab/service.py /root/work/fa-ownership-lab/service.pycd /root/work/fa-ownership-lab2. /root/work/fa-ownership-lab/service.py에서 principal(token, users)는 토큰 사전의 사용자 {id, scopes}를 반환하되 scopes 리스트까지 복사합니다. 모르는 토큰은 ValueError입니다.
3. /root/work/fa-ownership-lab/service.py에서 require_scope(user, scope)는 scopes에 scope 문자열이 정확히 있을 때 None, 없으면 PermissionError를 냅니다. read-all은 read가 아닙니다.
4. /root/work/fa-ownership-lab/service.py에서 visible(user, document)는 document가 None이 아니고 owner가 user의 id와 정확히 같을 때만 True입니다.
5. /root/work/fa-ownership-lab/service.py에서 public_document(document)는 id와 title만 가진 새 딕셔너리입니다. owner나 internal_cost는 포함하지 않습니다.
6. /root/work/fa-ownership-lab/service.py에서 authenticate(header, users)는 bearer와 principal을 연결합니다. ValueError는 HTTPException(401)이며 headers의 WWW-Authenticate 값은 Bearer입니다.
7. /root/work/fa-ownership-lab/service.py에서 read_document(user, documents, document_id)는 read scope 없으면 HTTPException(403), 없거나 남의 문서면 HTTPException(404), 아니면 public_document 결과입니다.
8. /root/work/fa-ownership-lab/service.py에서 create_app(users, documents)는 GET /documents/{document_id}에서 Authorization 헤더를 받아 authenticate와 read_document를 호출하는 FastAPI 앱을 반환합니다. 200·401·403·404와 비공개 필드 제거를 실제 요청으로 검증하세요.
참고
- 인터넷과 패키지 설치 없이 기존 lab-dev 환경에서 수행합니다.
- 각 단계는 45초 채점 예산 안에서 실행됩니다. 실제 sleep이나 네트워크 호출을 추가하지 마세요.
- 채점은 제출 모듈을 새로 불러오고 독립 입력과 임시 DB로 검사합니다. 예상값을 상수로 반환하는 대신 계약을 구현하세요.
- [FastAPI 공식 문서](https://fastapi.tiangolo.com/) · [pytest 공식 문서](https://docs.pytest.org/en/stable/) · [Python sqlite3](https://docs.python.org/3/library/sqlite3.html)
- 한계: 고정 토큰 사전은 교육용 입력이다. 운영 인증에는 만료·서명·폐기·안전한 보관이 추가로 필요하다. 404를 같게 만드는 것만으로 응답 시간이나 접근 로그를 통한 모든 추론이 사라지는 것도 아니다. 거절된 요청이 원본 데이터까지 바꾸지 않았는지 같이 검사한다.
8단계
- Bearer 헤더를 분리한다
- 신원을 복사해 반환한다
- 권한은 정확히 비교한다
- 소유권을 별도로 확인한다
- 응답 필드를 허용 목록으로 고른다
- 오류를 HTTP 계약에 맞춘다
- 거절 순서를 고정한다
- 실제 요청에서 경계를 닫는다