앱이 기대하는 base-backend 계약(envelope·JWT·/chat/stream SSE)을 그대로 구현. Django 는 로그인·세션 미러(SQLite/PG)·OpenCode 이벤트 번역만 맡고, 답변은 전용 OpenCode 인스턴스(opencode/ workspace, codeassist 에이전트)가 만듦. - accounts: 이메일 로그인, access 60분 / refresh 14일, entra/config 는 501 - chat: 세션 목록·검색·메시지·취소 + POST /chat/stream 어댑터(part.delta→token, idle→usage/done, 클라 끊겨도 턴 감시 태스크가 DB 마무리, 첫 이벤트 60초 타임아웃) - OpenCode 1.18 멀티 프로젝트라 모든 요청에 ?directory= 부착 - docs-lib 에 OpenCode SDK 1.18.6 타입 원본, pytest 32 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
44 lines
1.7 KiB
Python
44 lines
1.7 KiB
Python
"""JWT 인증 — Authorization: Bearer 헤더 또는 ?token= 쿼리(EventSource·다운로드용).
|
|
토큰 발급은 issue_tokens() — 프론트 TokenResponse 모양."""
|
|
|
|
from rest_framework_simplejwt.authentication import JWTAuthentication
|
|
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
|
|
from rest_framework_simplejwt.tokens import AccessToken, RefreshToken
|
|
|
|
|
|
class BearerOrQueryJWTAuthentication(JWTAuthentication):
|
|
def authenticate(self, request):
|
|
result = super().authenticate(request)
|
|
if result is not None:
|
|
return result
|
|
raw = request.query_params.get("token") if hasattr(request, "query_params") else None
|
|
raw = raw or request.GET.get("token")
|
|
if not raw:
|
|
return None
|
|
validated = self.get_validated_token(raw)
|
|
return self.get_user(validated), validated
|
|
|
|
|
|
def issue_tokens(user, refresh: RefreshToken | None = None) -> dict:
|
|
"""TokenResponse. refresh 를 주면 그걸 유지하고 access 만 새로 찍음(회전 안 함)."""
|
|
refresh = refresh or RefreshToken.for_user(user)
|
|
access = refresh.access_token
|
|
return {
|
|
"token": str(access),
|
|
"tokenExpirationTime": int(access["exp"]),
|
|
"refreshToken": str(refresh),
|
|
"refreshTokenExpirationTime": int(refresh["exp"]),
|
|
"tokenType": "bearer",
|
|
"user": user.as_payload(),
|
|
}
|
|
|
|
|
|
def user_from_token(raw: str):
|
|
"""순수 Django(async) 뷰용 — access 토큰 → 사용자, 실패 시 None."""
|
|
if not raw:
|
|
return None
|
|
try:
|
|
return BearerOrQueryJWTAuthentication().get_user(AccessToken(raw))
|
|
except (InvalidToken, TokenError, Exception):
|
|
return None
|