-
기본 장고에서 JWT를 활용한 로그인 구현Django 2022. 3. 27. 14:23
오늘은 기본 장고에서 기존 csrf 세션 방식이 아닌 JWT를 활용하여 로그인을 구현해보려고 한다.
일단 간단하게 구현 방식을 설명하자면
1. 사용자가 로그인을 하게되면 서버에서 사용자를 확인 후 Access Token 발급
2. 발급된 토큰을 cookie에 저장
3. 사용자가 데이터 요청시 Access Token을 보냄
4. 서버에서 Access Token을 검증 후 응답
1. package install
PyJWT 와 django-dotenv를 insall 해준다.
2. 프로젝트 폴더에 .env 파일을 생성한다.
SECRET_KEY= (secret_key) JWT_ALGORITHM="HS256"
secret_key는 프로젝트를 생성하면 settings.py에 발급되는SECRET_KEY이다.
또한 csrf 토큰은 사용하지 않을 것이기 때문에 settings.py / MIDDLEWARE 의 csrf관련 코드를 주석처리 하자.
3. users앱에 utils폴더를 만든 후 jwt.py를 생성한다.(vscode를 사용하면 __init__.py도 생성해야함)
import jwt from django.conf import settings JWT_ALGORITHM = getattr(settings, 'JWT_ALGORITHM', None) SECRET_KEY = getattr(settings, 'SECRET_KEY', None) def encode_jwt(data): return jwt.encode(data, SECRET_KEY, algorithm=JWT_ALGORITHM) def decode_jwt(access_token): return jwt.decode( access_token, SECRET_KEY, algorithms=[JWT_ALGORITHM], issuer="Bookin", options={"verify_aud": False}, )
encode_jwt : jwt를 암호화하는 함수
decode_jwt : 암호화된 토큰을 decode하는 함수
issuer : 발급자 ( 원하는 이름으로 사용한다. )
4. 토큰 발급, 로그인 데코레이터 코드
토큰을 사용한 인증/인가는 프로젝트 전반적인 모든 곳에서 사용한다고 생각했기 때문에 core앱을 만들고 utils.py에 코드를 작성하였음
core/utils.py
from django.shortcuts import render import jwt from users.utils.jwt import encode_jwt, decode_jwt from users.models import UserModel from datetime import datetime, timedelta def generate_access_token(email): iat = datetime.now() exp = iat + timedelta(days=5) data = { "iat": iat.timestamp(), "exp": exp.timestamp(), "aud": email, "iss": "Bookin", } return encode_jwt(data) def login_authenticate(request, email, page): data = {} data["access_token"] = generate_access_token(email) data["email"] = email user = UserModel.objects.get(email=data["email"]) response = render(request, page) response.set_cookie('access_token', data['access_token']) return response def login_decorator(func): def wrapper(request, *args, **kwargs): try: access_token = request.COOKIES['access_token'] payload = decode_jwt(access_token) user = UserModel.objects.get(email=payload["aud"]) request.user = user except jwt.exceptions.DecodeError: print('INVALID ERROR') request.user except KeyError: print('KEY ERROR') request.user return func(request, *args, **kwargs) return wrapper def authentication(request): email = request.user user = UserModel.objects.get(email=email) return user
1. generate_access_token 함수는 토큰을 발급하는 함수이다.
iat : 발행일
exp : 만료일 (5일)
aud : email로 한 이유는 email을 unique field로 지정해놨기 떄문에 email로 작성했다.
iss : 발급자로 위 jwt.py에 작성한 issuer 와 같은 이름으로 해야 한다.
2. login_authenticate 함수는 generate_access_token함수를 사용하여 토큰을 발급하고 인증받는 함수이다.
set_cookie() 함수를 사용하여 발급된 토큰을 cookie에 저장한다.
3. login_decorator 함수는 로그인 인증을 받아야하는 기능을 간편하게 사용하기위해 decorator로 함수를 만들었다.
토큰 인증을 받은 사용자만 기능을 사용할 수 있다.
아래 sign_in_view 함수를 보면 함수위에 @login_decorator를 추가해주는 방식으로 사용할 수 있다.
로그인 인증이 필요한 기능에 @login_decorator를 붙여주자.
4. authentication 함수는 View에서 GET으로 요청이 들어왔을 때 인증받은 사용자를 구분하기위해 작성하였다.
5. View 작성
@login_decorator def sign_in_view(request): if request.method == 'POST': email = request.POST.get('email', '') password = request.POST.get('password', '') me = auth.authenticate(request, email=email, password=password) page = 'bookstore/main.html' if me is not None: return login_authenticate(request, email, page) else: return render(request, 'users/signin.html', {'error': '비밀번호를 확인해주세여'}) if request.method == 'GET': try: user = authentication(request) if user: return render(request, 'bookstore/main.html') except Exception: return render(request, 'users/signin.html') @login_decorator def user_logout(rqeuest): reset = '' response = redirect("/sign-in") response.set_cookie('access_token', reset) return response
logout을 하면 쿠키에 들어있는 access_token은 비어진다.
위 코드들은 유효성 검사와, 보안 사항이 조금 미흡한 코드이다. 기본장고에서 JWT가 어떻게 생성되고 사용될 수 있는지 참고만 하였으면 좋겠다.
원래는 아래 그림과 같은 과정으로 코드 구현을 해야한다.
refresh_token 또한 발급이 되면 해커가 access_token을 중간에 탈취하더라도 만료 시간이 짧아 보안상 유리하다.
refresh_token을 발급할 때 같은 로그인 한 user의 DB에도 refresh_token이 저장이되고
access_token이 만료되면 쿠키에 있는refresh_token과 DB에 있는 토큰이 같은지 확인하고 새로운 access_token을 발급해준다.
'Django' 카테고리의 다른 글
Django 이메일 인증으로 비밀번호 찾기 기능 구현(SMTP) (0) 2022.04.07 Django ninja JWT를 활용하여 로그인 구현 (0) 2022.03.14 Django allauth Google Login page가 바로 안보일 때 (0) 2022.02.26 Django Unit Test in VSCode (0) 2022.02.20 Poetry 와 package (0) 2022.02.20