[TIL_Carrotww] 69 - 22/12/09

μœ ν˜•μ„Β·2022λ…„ 12μ›” 11일
0

TIL

λͺ©λ‘ 보기
81/138
post-thumbnail

πŸ“Carrotww의 μ½”λ”© 기둝μž₯

🧲 django Channels 인증

πŸ” μ €λ²ˆ ν¬μŠ€νŒ…μ— channels 인증에 κ΄€ν•œ 글을 썼닀.
ν•˜μ§€λ§Œ μ‹€μ œ ν…ŒμŠ€νŠΈλ₯Ό ν•΄λ³΄λ‹ˆ λ‚΄κ°€ μ›ν•˜λŠ” μ‚¬μš©μžλ‘œ 인증이 λ˜μ§€ μ•Šμ•˜μ—ˆλ‹€.
μ§€κΈˆλΆ€ν„° ν•˜λ‚˜μ”© λœ―μ–΄λ³΄λ €κ³  ν•œλ‹€.

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        # 둜그인된 μ‚¬μš©μžμΈμ§€ 확인
        if self.scope['user']:
            pass
        else:
            self.close()
        await self.accept()

λ‚˜λŠ” μœ„μ™€κ°™μ΄ κ°„λ‹¨ν•˜κ²Œ scope에 λ‹΄κΈ΄ userλ₯Ό ν™•μΈν•˜μ—¬ 인증 μˆ˜ν–‰μ„ ν…ŒμŠ€νŠΈ ν–ˆλ‹€.
ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰ν•˜λŠ”λ° 계속 ν•œ μ‚¬μš©μžμ˜ μ •λ³΄λ§Œ λ“€μ–΄μ™”λ‹€. 이게 μ˜μ•„ν•˜μ—¬ scope data찍어봀닀.

{'asgi': {'version': '3.0'},
 'client': ['127.0.0.1', 54699],
 'cookies': {'csrftoken': 'FFQG53vwTjHdfsPEkHyF3iu24FHSdq4M27yVrDV8IXeW2fIxzI2gOu1yRckbU5VT',
             'sessionid': 'mccrs5c1rk52kdibw1l469tak3x2elnv'},
 'headers': [(b'host', b'127.0.0.1:8000'),
             (b'connection', b'Upgrade'),
             (b'pragma', b'no-cache'),
             (b'cache-control', b'no-cache'),
             (b'user-agent',
              b'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'  
              b' (KHTML, like Gecko) Chrome/106.0.5249.207 Whale/3.17.145.18'  
              b' Safari/537.36'),
             (b'upgrade', b'websocket'),
             (b'origin', b'http://127.0.0.1:5500'),
             (b'sec-websocket-version', b'13'),
             (b'accept-encoding', b'gzip, deflate, br'),
             (b'accept-language', b'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7'),     
             (b'cookie',
              b'csrftoken=FFQG53vwTjHdfsPEkHyF3iu24FHSdq4M27yVrDV8IXeW2fIxzI'  
              b'2gOu1yRckbU5VT; sessionid=mccrs5c1rk52kdibw1l469tak3x2elnv'),  
             (b'sec-websocket-key', b'tF4uRtVXNpr55l9KcDoD8w=='),
             (b'sec-websocket-extensions',
              b'permessage-deflate; client_max_window_bits')],
 'path': '/ws/socket-server/1/',
 'path_remaining': '',
 'query_string': b'',
 'raw_path': b'/ws/socket-server/1/',
 'server': ['127.0.0.1', 8000],
 'session': <django.utils.functional.LazyObject object at 0x00000237C83AFD60>, 
 'subprotocols': [],
 'type': 'websocket',
 'url_route': {'args': (), 'kwargs': {'room_id': 1}},
 'user': <channels.auth.UserLazyObject object at 0x00000237C83AFB50>}

보면 'user' 뢀뢄이
channels.auth.UserLazyObject λ₯Ό μ‚¬μš©μ€‘μΈκ²ƒμ„ μ•Œ 수 μžˆμ—ˆλ‹€.
λ‚œ channels.auth 에 AuthMiddlesareStack 을 μ‚¬μš©ν•˜κ³  μžˆμ–΄ ν•΄λ‹Ή ν•¨μˆ˜λ‘œ λ“€μ–΄κ°€λ³΄μ•˜λ‹€.

class AuthMiddleware(BaseMiddleware):
    """
    Middleware which populates scope["user"] from a Django session.
    Requires SessionMiddleware to function.
    """

    def populate_scope(self, scope):
        # Make sure we have a session
        if "session" not in scope:
            raise ValueError(
                "AuthMiddleware cannot find session in scope. "
                "SessionMiddleware must be above it."
            )
        # Add it to the scope if it's not there already
        if "user" not in scope:
            scope["user"] = UserLazyObject()

    async def resolve_scope(self, scope):
        scope["user"]._wrapped = await get_user(scope)

    async def __call__(self, scope, receive, send):
        scope = dict(scope)
        # Scope injection/mutation per this middleware's needs.
        self.populate_scope(scope)
        # Grab the finalized/resolved scope
        await self.resolve_scope(scope)

        return await super().__call__(scope, receive, send)

scope ν•¨μˆ˜μ˜ user λ°μ΄ν„°λŠ” get_user(scope)λ₯Ό 톡해 데이터λ₯Ό κ°€μ Έμ˜€κ³  μžˆμ—ˆκ³  ν•΄λ‹Ή ν•¨μˆ˜λŠ”

@database_sync_to_async
def get_user(scope):
    """
    Return the user model instance associated with the given scope.
    If no user is retrieved, return an instance of `AnonymousUser`.
    """
    # postpone model import to avoid ImproperlyConfigured error before Django
    # setup is complete.
    from django.contrib.auth.models import AnonymousUser

    if "session" not in scope:
        raise ValueError(
            "Cannot find session in scope. You should wrap your consumer in "
            "SessionMiddleware."
        )
    session = scope["session"]
    user = None
    try:
        user_id = _get_user_session_key(session)
        backend_path = session[BACKEND_SESSION_KEY]
    except KeyError:
        pass
    else:
        if backend_path in settings.AUTHENTICATION_BACKENDS:
            backend = load_backend(backend_path)
            user = backend.get_user(user_id)
            # Verify the session
            if hasattr(user, "get_session_auth_hash"):
                session_hash = session.get(HASH_SESSION_KEY)
                session_hash_verified = session_hash and constant_time_compare(
                    session_hash, user.get_session_auth_hash()
                )
                if not session_hash_verified:
                    session.flush()
                    user = None
    return user or AnonymousUser()

μ„Έμ…˜ 정보λ₯Ό ν†΅ν•΄μ„œ κ°€μ Έμ˜€κ³  μžˆμ–΄μ„œ μ œλŒ€λ‘œ user 데이터λ₯Ό λͺ» κ°€μ Έμ™”λ˜ 것이닀.
이 뢀뢄을 ν•΄κ²°ν•˜λ €λ©΄ μ €λ²ˆ ν¬μŠ€νŒ…μ—μ„œ μ–ΈκΈ‰ν–ˆλ˜ 것 처럼 근본적으둜 midlewareλ₯Ό λ‚΄κ°€ μ»€μŠ€ν…€ν•΄μ„œ μ‚¬μš©ν•˜λ©΄ λœλ‹€.

profile
Carrot_hyeong

0개의 λŒ“κΈ€