계정 생성 API 가 아예 없었다(그동안 users 를 손으로 INSERT 했다). 로그인 화면은 있는데 그 뒤에 설 계정을 만들 방법이 제품에 없는 상태였다. - auth_service.signup: 가입 = **새 회사(테넌트) 1개 + 첫 계정 1개**. users.company_id 가 NOT NULL 이고 모든 도메인이 company 로 스코프돼서, 회사 없는 계정은 아무것도 못 만든다 - services/external/google_identity: 구글 ID 토큰의 서명·iss·만료에 더해 **aud(우리 client_id)와 email_verified 를 본다.** aud 검사가 빠지면 남의 앱에 발급된 '진짜' 구글 토큰으로 우리 계정에 들어온다 — 서명도 발급자도 전부 맞으므로 다른 검사로는 안 걸린다 - users.provider/provider_uid 추가, password NULL 허용, id 20→64자(google_<sub> 가 20자를 넘는다). provider 에 server_default 를 같이 준 이유: ORM default 는 raw INSERT(테스트 시드)에 안 먹어서 NOT NULL 컬럼이면 그 경로가 통째로 깨진다 - attempt_login: 소셜 계정을 먼저 끊는다. 안 끊으면 bcrypt 가 None 해시를 만나 500 이다 - 같은 이메일이라도 id/pw 계정과 구글 계정을 **잇지 않는다.** 이으면 계정 선점이다 — 남의 이메일로 먼저 만들어 둔 계정에 그 사람의 구글 로그인이 들어간다 → DECISIONS 1-5 - LoginPage 는 admin 과 공유라 selfServe 로 갈랐다. admin 은 가입 링크도 구글 버튼도 안 뜬다 (admin 라우터에 /signup 이 없어 404 가 난다) - GOOGLE_CLIENT_ID 는 루트 .env 한 곳. compose 가 VITE_GOOGLE_CLIENT_ID 로 흘려보낸다 — 두 곳에 적으면 백엔드 aud 대조와 화면 버튼이 조용히 갈라진다 ★ 이미 도는 DB 는 init.sql 을 다시 적용해야 한다(말미 ALTER 섹션). pytest: auth 13건 + 구글 토큰 검증 8건(진짜 RSA 서명으로 aud·iss·만료·email_verified·변조 거절 확인) 통과. 전체 527 passed / 8 failed(전부 기존 실패, 인증과 무관). tsc·eslint·vite build 통과.
31 lines
1.2 KiB
Python
31 lines
1.2 KiB
Python
"""설정 싱글턴 — 호출부 21개 파일이 이 이름들을 가져다 쓴다."""
|
|
|
|
from config.config_models import (
|
|
APP_ENV, # 재export — 테스트가 "지금 어느 환경으로 도는가" 를 여기서 읽는다(tests/test_config.py)
|
|
ExternalApiConfig,
|
|
GoogleOAuthConfig,
|
|
JwtToken,
|
|
LogConfig,
|
|
MainDBConfig,
|
|
WebServerConfig,
|
|
get_external_api_config,
|
|
get_google_oauth_config,
|
|
get_jwt_token_config,
|
|
get_log_config,
|
|
get_main_db_config,
|
|
get_web_server_config,
|
|
)
|
|
|
|
web_server_config: WebServerConfig = get_web_server_config()
|
|
log_config: LogConfig = get_log_config()
|
|
main_db_config: MainDBConfig = get_main_db_config()
|
|
jwt_token_config: JwtToken = get_jwt_token_config()
|
|
external_api_config: ExternalApiConfig = get_external_api_config()
|
|
google_oauth_config: GoogleOAuthConfig = get_google_oauth_config()
|
|
|
|
# 부팅은 막지 않는다 — 토큰이 필요 없는 로컬 작업까지 못 하게 되면 곤란하다.
|
|
if not jwt_token_config.access_key or not jwt_token_config.refresh_key:
|
|
from common.logger import LOG
|
|
|
|
LOG.w("[보안] JWT 시크릿이 비어 있습니다 — .env 에 JWT_ACCESS_SECRET / JWT_REFRESH_SECRET 를 넣으세요.")
|