- POST /v1/auth/logout: 저장된 access/refresh 토큰 행 삭제 → 즉시 로그아웃 - /me, refresh 에서 제시된 토큰을 저장된 토큰과 대조(불일치 시 TOKEN_REVOKED=1203) → 로그아웃/타기기 재로그인으로 교체된 토큰을 만료 전이라도 차단 - crud get_token 추가, ErrorType.TOKEN_REVOKED(1203) 추가, Res_Logout 프로토콜 - 로그아웃/단일세션 무효화 e2e 테스트 추가 (test_auth.py) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
90 lines
3.6 KiB
Python
90 lines
3.6 KiB
Python
from enum import Enum, auto
|
|
|
|
from fastapi import HTTPException
|
|
|
|
|
|
class ErrorType(Enum):
|
|
"""서버 전역 결과 코드. Res_WebPacketProtocol.result 에 담겨 클라이언트로 전달된다.
|
|
HTTP status 와 겹치지 않도록 구간을 분리해서 관리한다.
|
|
"""
|
|
|
|
SUCCESS = 0
|
|
FAIL = 1
|
|
|
|
# DB / Redis 에러
|
|
DB_RUN_FAILED = 10
|
|
DB_ALREADY_SAME_KEY = auto()
|
|
DB_INVALID_KEY = auto()
|
|
DB_EMPTY_DATA = auto()
|
|
DB_INVALID_TYPE = auto()
|
|
|
|
# 요청/직렬화 에러
|
|
JSON_PARSE_ERROR = 100
|
|
INVALID_REQUEST_DATA = auto()
|
|
INTERNAL_EXCEPTION = auto()
|
|
|
|
# http 에러 코드와 겹치지 않게 설정 - router 전용 예외 발생 옵션
|
|
HTTP_INVALID_CLIENT_REQUEST = 419
|
|
HTTP_TO_MANY_REQUEST = 429
|
|
HTTP_INVALID_CLIENT_ACCESS = 433
|
|
HTTP_ACCESS_TOKEN_EXPIRED = 434
|
|
HTTP_REFRESH_TOKEN_EXPIRED = 435
|
|
HTTP_INVALID_TOKEN_ACCESS = 436
|
|
|
|
# 계정 관련 에러
|
|
ACCOUNT_INVALID_INFO = 1200
|
|
ACCOUNT_ALREADY_EXIST = auto()
|
|
ACCOUNT_BLOCKED_USER = auto()
|
|
TOKEN_REVOKED = auto() # 제시된 토큰이 저장된 토큰과 불일치(로그아웃/타기기 로그인으로 교체됨)
|
|
|
|
|
|
# ErrorType 의 HTTP_* 값과 status_code 를 맞춰 router 단에서 raise 한다.
|
|
EXCEPTION_INVALID_CLIENT_REQUEST = HTTPException(status_code=ErrorType.HTTP_INVALID_CLIENT_REQUEST.value, detail=ErrorType.HTTP_INVALID_CLIENT_REQUEST.name)
|
|
EXCEPTION_TO_MANY_REQUEST = HTTPException(status_code=ErrorType.HTTP_TO_MANY_REQUEST.value, detail=ErrorType.HTTP_TO_MANY_REQUEST.name)
|
|
EXCEPTION_INVALID_CLIENT_ACCESS = HTTPException(status_code=ErrorType.HTTP_INVALID_CLIENT_ACCESS.value, detail=ErrorType.HTTP_INVALID_CLIENT_ACCESS.name)
|
|
EXCEPTION_ACCESS_TOKEN_EXPIRED = HTTPException(status_code=ErrorType.HTTP_ACCESS_TOKEN_EXPIRED.value, detail=ErrorType.HTTP_ACCESS_TOKEN_EXPIRED.name)
|
|
EXCEPTION_REFRESH_TOKEN_EXPIRED = HTTPException(status_code=ErrorType.HTTP_REFRESH_TOKEN_EXPIRED.value, detail=ErrorType.HTTP_REFRESH_TOKEN_EXPIRED.name)
|
|
EXCEPTION_HTTP_INVALID_TOKEN_ACCESS = HTTPException(status_code=ErrorType.HTTP_INVALID_TOKEN_ACCESS.value, detail=ErrorType.HTTP_INVALID_TOKEN_ACCESS.name)
|
|
|
|
|
|
class DBType(Enum):
|
|
"""논리 DB 구분. 모델마다 DBType() 으로 자신이 속한 DB 를 반환한다.
|
|
DB 가 늘어나면 여기에 추가하고 db_session_manager 의 맵에 등록만 하면 된다.
|
|
물리적으로 같은 negosium_db 라도 도메인별 논리 구분으로 나눠 둘 수 있다(커넥션 config 는 재사용).
|
|
"""
|
|
|
|
USER = 1 # 기본 유저 (supplier_users 테이블)
|
|
PARTNER = 2 # partner 도메인 (partner.suppliers 등)
|
|
|
|
|
|
class DBWRType(Enum):
|
|
"""Read / Write 접속 구분. 조회는 DB_READ, 변경은 DB_WRITE 엔진을 사용한다."""
|
|
|
|
DB_READ = 1
|
|
DB_WRITE = 2
|
|
|
|
|
|
# ============================================================
|
|
# 도메인 코드값. 스키마는 SMALLINT 정수 코드(1부터)로 두고, 의미 매핑은 여기 enum 으로 한다.
|
|
# (postgres-init/01-schema.sql: "코드값(status/role/type 등)은 SMALLINT 정수 코드로 둔다")
|
|
# ============================================================
|
|
class AccountStatus(Enum):
|
|
"""계정 상태 코드. company.users / supplier.supplier_users 의 status 컬럼."""
|
|
|
|
ACTIVE = 1 # 활성
|
|
INACTIVE = 2 # 비활성
|
|
|
|
|
|
class UserRole(Enum):
|
|
"""유저 권한 코드. company.users / supplier.supplier_users 의 role 컬럼."""
|
|
|
|
USER = 1 # 일반 유저
|
|
MANAGER = 2 # 매니저
|
|
|
|
|
|
class TokenType(Enum):
|
|
"""토큰 종류 코드. supplier.supplier_user_tokens 의 type 컬럼."""
|
|
|
|
ACCESS = 1
|
|
REFRESH = 2
|