Django의 JWT 인증

17152 단어 djangopythonjwt

1. 인증 및 승인



입증



인증은 사람이나 장치의 신원을 확인하는 프로세스입니다. 인증 프로세스 중 하나는 로그인 프로세스입니다. 웹사이트에 가입하면 귀하의 정보(아이디, 비밀번호, 이름, 이메일 등)가 데이터베이스에 저장됩니다. 그 후에는 정보를 제공하기 위해 계정을 만들 필요가 없습니다. 오히려, 귀하는 귀하의 신원을 확인하기 위해 귀하의 사용자 ID와 암호를 제공하기만 하면 웹 사이트는 자동으로 액세스하는 사람이 귀하임을 알게 됩니다.

권한 부여



권한 부여는 사용자 권한 또는 액세스 수준을 결정하는 데 사용되는 보안 메커니즘입니다. 많은 커뮤니티 사이트에서 게시물을 올린 사람과 관리자만 삭제할 수 있습니다. 다른 사람이 게시물을 삭제하려고 하면 웹사이트에서 오류가 발생해야 합니다(그러나 대부분의 경우 삭제 버튼조차 볼 수 없습니다). 따라서 각 요청에 대해 사용자는 권한이 있음을 증명해야 합니다.

2. JWT



JWT란?



JWT(JSON Web Token)는 당사자 간에 정보를 JSON 개체( link )로 안전하게 전송하기 위한 간결하고 독립적인 방법을 정의하는 개방형 표준(RFC 7519)입니다. JWT를 사용하여 요청을 인증하고 승인할 수 있습니다.
JWT는 세 개의 연결된 Base64url 인코딩 문자열(헤더, 페이로드 및 서명)로 구성되며 점(.)으로 구분됩니다. 헤더에는 토큰 유형 및 암호화 알고리즘에 대한 메타데이터가 포함됩니다. 서명은 토큰의 신뢰성을 확인하는 데 사용됩니다. 그리고 페이로드에는 인증 및 권한 부여에 필요한 모든 데이터가 포함되어 있습니다.


JWT 저장



세션 또는 로컬 저장소



사용자가 로그인하면 서버는 JWT를 생성하여 클라이언트 측으로 보냅니다. 그런 다음 클라이언트 측은 이를 세션 저장소 또는 로컬 저장소에 저장합니다. 클라이언트 측에서 인증 또는 승인이 필요한 요청을 서버 측에 보낼 때마다 JWT가 Authorization Header로 전송됩니다.

XSS(Cross Site Scripting) 공격에 취약

세션 및 로컬 저장소는 JavaScript를 통해 액세스할 수 있습니다. 악의적인 제3자가 자신의 JS를 웹 사이트에 삽입하여 API에 요청할 수 있습니다.

쿠키



서버는 JWT를 쿠키에 저장하고 쿠키에 저장된 JWT로 사용자를 확인합니다.

CSRF(Cross Site Request Forgery) 공격에 취약

쿠키는 각 요청과 함께 전송되기 때문에 CSRF에 취약합니다. 따라서 악의적인 제3자가 의도하지 않은 요청을 쉽게 만들 수 있습니다.

장고의 JWT




# my_settings.py
# NEVER EVER COMMIT THIS FILE TO GIT

SECRET = {
    'SECRET_KEY': 'abcde1234',
    'JWT_ALGORITHM': 'HS256'
}



# settings.py

import my_settings

SECRET_KEY = my_settings.SECRET['SECRET_KEY']
JWT_ALGORITHM = my_settings.SECRET['JWT_ALGORITHM']



# user/views.py

import json
from datetime import datetime, timdelta
from django.conf import settings
from django.http import JsonResponse
from django.views import View

import bcrypt
import jwt
from .models import User
from token_utils import user_token

class UserSignInView(View):
    def post(self, request):
        try:
            data = json.loads(request.body)
            username = data['username']
            pw_input = data['password']
            user = User.objects.filter(username=username).first()

            if user is None:
                return JsonResponse({"message": "INVALID_USERNAME"}, status=401)
            if bcrypt.checkpw(pw_input.encode('utf-8'),
                              user.password.encode('utf-8')):
                key = settings.SECRET_KEY
                algorithm = settings.JWT_ALGORITHM
                token = jwt.encode(
                    {
                        'iss': 'me',
                        'id': user.id,
                        'exp': datetime.utcnow() + timedelta(days=14)
                    }, key, algorithm=algorithm).decode('utf-8')

                response = JsonResponse(
                    {
                        'message': 'SUCCESS'
                    }, status=200
                )

                # when using Local/Session Storage instead of Cookie, just send token in JsonResponse
                if data.get('remember_me') is not None:
                    max_age = 14*24*60*60 # 14 days
                    expires = datetime.strftime(
                        datetime.utcnow() + timedelta(seconds=max_age),
                        "%Y-%m-%d %H:%M:%S"
                    )
                    response.set_cookie(
                        'token',
                        token,
                        max_age=max_age,
                        expires=expires,
                        httponly=True
                    )
                    return response

                response.set_cookie(
                    'token',
                    token,
                    max_age=None,
                    expires=None,
                    httponly=True
                )
                return response

            return JsonResponse({"message": "WRONG_PASSWORD"}, status=401)

        except KeyError as e:
            return JsonResponse({'message': f'KEY_ERROR: {e}'}, status=400)
        except ValueError as e:
            return JsonResponse({'message': f'VALUE_ERROR: {e}'}, status=400)




# token_utils.py

import json
from django.conf import settings
from django.http import JsonResponse

import jwt
from user.models import User

def user_token(func):
    def wrapper(self, request, *args, **kwargs):
        try:
            token = request.COOKIES.get('token')
            # token = request.headers.get('token')

            key = settings.SECRET_KEY
            algorithm = settings.JWT_ALGORITHM

            if token is None:
                return JsonResponse({"message": "INVALID_TOKEN"}, status=401)

            decode = jwt.decode(token, key, algorithm=algorithm)
            request.user = User.objects.get(id=decode['id'])

        except jwt.ExpiredSignatureError:
            return JsonResponse({"message": "EXPIRED_TOKEN"}, status=400)
        return func(self, request, *args, **kwargs)
    return wrapper

좋은 웹페이지 즐겨찾기