Closed UkiDelly closed 11 months ago
웹소켓에 인증을 구현하기 위해 다음과 같이 AuthMiddlewareStack
미들웨어를 사용
# asgi.py
application = ProtocolTypeRouter(
{
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
AllowedHostsOriginValidator(
URLRouter([re_path(r"chat/(?P<room_name>\w+)/$", ChatConsumer.as_asgi())])
)
)
}
)
하지만 해당 미들웨어는 세션 방식을 사용하기에 JWT를 사용하는 현재 상황에 알맞지 않은 방식, 그래서 구글링을 통해 다음과 같이 다른사람의 코드를 긁어옴
# user_id로 유저를 찾아서 유저 객체를 반환
@database_sync_to_async
def get_user(user_id):
try:
return User.objects.get(id=user_id)
except User.DoesNotExist:
return AnonymousUser()
class WebSocketJWTAuthMiddleware(BaseMiddleware)::
def __init__(self, inner):
self.inner = inner
async def __call__(self, scope, receive, send):
authorization_header = next(
(header for header in scope["headers"] if header[0] == b"cookie"), None
)
if authorization_header:
token = (
authorization_header[1].decode("utf-8").split("=")[-1]
)
else:
token = None
try:
access_token = AccessToken(token)
# 에러 발생 ~~ user_id 값이 존재하지 않음
scope["user"] = await get_user(access_token["user_id"])
except TokenError:
scope["user"] = AnonymousUser()
print("user : ", scope["user"])
return await super().__call__(scope, receive, send)
하지만 위 방식을 사용해도 JWT를 가져오지 못함, 디버그 모드와 브레이크 포인트를 사용해서 확인해 본 결과
authorization_header = next(
(header for header in scope["headers"] if header[0] == b"cookie"), None
)
여기서부터 문제가 시작됨. 위 코드는 b"cookie"
에서 JWT를 추출하지만, JWT는 b"authorization"
에 존재했음 그래서 해당 코드를 다음과 같이 수정함
authorization_header = next(
(header for header in scope["headers"] if header[0] == b"authorization"), None
)
정상적으로 JWT가 있는 헤더값을 추출 그런 다음,
# ("authorization","Bearer 토큰")
token = (
authorization_header[1].decode("utf-8").split("=")[-1]
)
이 코드를 다음으로 수정
# ("authorization","Bearer 토큰")
token = (
authorization_header[1].decode("utf-8").split(" ")[-1]
)
token
에 정상적으로 jwt 토큰이 담겨지는걸 확인하고 검증을 통해 user_id
를 추출하게 되어 문제 해결
개인키를 발급 받아서 사용하려고 했지만 다음과 같은 에러가 발생
openai.RateLimitError: Error code: 429 - {'error': {'message': 'You exceeded your current quota, please check your plan and billing details.', 'type': 'insufficient_quota', 'param': None, 'code': 'insufficient_quota'}}
Api Key를 삭제하고 여러번 발급해도 계속 같은 문제가 발생해서 Api Key 요청해서 사용하기로 결정함
플러터 웹을 사용하면, 네트워크 통신을 담당 하는 dio
와 상태관리를 담당하는 riverpod
에서 오류 발생
지속적으로 해결방법을 찾겠지만 현재로썬 새로고침을 봉인
서버에서 JWT를 header
로 받아 인증처리하는 로직을 작성하고, Postman같은 http 테스트 프로그램을 사용할때는 정상적으로 작동,
하지만 프론트에서 웹소켓의 header에 값을 추가할수 있는 방법이 존재 하지 않아서 인증이 되지 않아 접속이 불가능,
사용자 인증은 프론트에게 인가하고 서버에서는 인증 없이 웹소켓에 연결할 수 있도록 서버를 수정
AsyncJswonWebSocket
을 사용해서 웹소켓을 처리하고 있었는데, Postman에서 json 형식으로 데이터를 전송할때는 문제 발생 X
프론트에서 json형식으로 전송하면, {'message' : 'message'}
이렇게 큰 따옴표가 아닌 작은 따옴표로 전송되어 서버에서 변환 했을때 문제가 발생, 프론트쪽에서 큰 따옴표를 사용하도록 여러가지 방법을 썻지만, 실패하고 서버를 AsyncJsonWebSocket
에서 AsyncWebSocket
으로 수정하여 json 형식이 아닌 단순 문자열 형식으로 데이터를 주고 받도록 수정하여 문제 해결
유저당 하루 요청 가능한 횟수를 제한하기 위해 User
모델에 채팅 횟수를 기록하는 기능을 구현했지만, 자정이 되었을때 이를 초기화를 할 방법에 대해 모색함.
crontab
이라는 모듈을 발견하고 사용법을 알게 되었고, 다음과 같은 함수를 cron.py
에 추가
def reset_chat_count():
MyUser.objects.update(chat_count=0)
그리고 settings.py
파일에 다음과 같은 항목을 추가
# Cron Jobs
CRONJOBS = [
('* 0 * * *', 'chat.cron.reset_chat_count')
]
그리고 다음과 같은 명령어를 입력하여 cron 태스크를 추가함
python manage.py crontab add
이로써 서버가 돌아가고 있을때 자정이 넘어가면 자동으로 cron 태크스를 시작해서 모든 유저의 요청 가능 횟수를 0으로 업데이트 하는 코드가 동작하도록 하여 해결했지만, 테스트는 진행하지 못함
개발하면서 발생한 이슈 및 문제들