JWT๋ก ๋ก๊ทธ์์ ๊ตฌํํ๊ธฐ
jwt ํ ํฐ์ผ๋ก ๋ก๊ทธ์์์ ํ ์ ์์๊น?
๊ฐ๊ณ๋ถ ์๋น์ค์์ jwt๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๊ทธ์ธ ํ ํฐ์ ๋ฐ๊ธํ์๋ค. ๊ทธ๋ฐ๋ฐ jwt ํ ํฐ์ผ๋ก ๋ก๊ทธ์์์ ํ๋ ค๋ ์ด๋ป๊ฒ ํด์ผ ํ ์ง ๋ชจ๋ฅด๊ฒ ์ด์ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋ ค ํ๋ค.
JWT ๋ก๊ทธ์ธ
JWT ํ ํฐ์ ์๋๋ฐฉ์์ ์ด๋ ๋ค.
- ์ ์ ๊ฐ ๋ก๊ทธ์ธ์ ํ๋ค.
- db์์ ์ ์ ์ ๋ณด๋ฅผ ์กฐํํ ๋ค ์ ์ ์ ๋ณด๊ฐ ์ผ์นํ๋ฉด ๋ก๊ทธ์ธ๊ณผ ๋์์ JWT ํ ํฐ์ ๋ฐ๊ธํ๋ค.
- ํ ํฐ์ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํ๋ค.
- ํด๋ผ์ด์ธํธ์์ api ์์ฒญ์ ํ ๋ ํ ํฐ์ Authorization header์ ๋ด์์ ๋ณด๋ธ๋ค.
- ์๋ฒ๋ ํ ํฐ์ decodeํ์ฌ ์ ์ ์ ๋ณด๋ฅผ ํ๋ํ๋ค.
- db์ ํ ํฐ์์ ์ป์ ์ ์ ์ ๋ณด์ ์ผ์นํ๋ ์ ์ ๊ฐ ์์ ์ ์๋ฌ๋ฅผ ๋ฐํํ๊ณ ์ ์ ๊ฐ ์กด์ฌํ ์ api ์์ฒญ์ ์๋ต์ ๋ฐ์ ์ ์๋ค.
๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์ ์ ์ ๊ฐ ๋ก๊ทธ์ธ ํ ์๋น์ค ์ด์ฉ์ ํ๋ค ๋ก๊ทธ์์์ ํ๊ณ ์ถ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
JWT ๋ก๊ทธ์์
https://medium.com/devgorilla/how-to-log-out-when-using-jwt-a8c7823e8a6
์ ๊ธ์ ๋ฐ๋ผ ํด๊ฒฐ์ฑ ์ ์ฐพ์๋ณด๋ คํ๋ค.
โ ๋ด๊ฐ ์๊ฐํ ๋ฐฉ๋ฒ ๐
๋ก๊ทธ์์ ์ ํ ํฐ์ ์ ํจ๊ธฐ๊ฐ์ ๊ฐ์ ๋ก ๋๋ผ ์ ์๋ค๋ฉด ๋ก๊ทธ์์์ด ๋์ง ์์๊น..?โOkay, so letโs log out the user from the backend!โ you would say. But hold down the horses. Itโs not that simple with JWT. You cannot delete the session or cookie and get going. Actually, JWT serves a different purpose than a session and it is not possible to forcefully delete or invalidate an existing token.
"์, ์ด์ ๋ฐฑ์๋์์ ์ฌ์ฉ์๋ฅผ ๋ก๊ทธ์์์์ผ ๋ณด๊ฒ ์ต๋๋ค!"๋ผ๊ณ ๋งํฉ๋๋ค. ํ์ง๋ง ๋ง๋ค์ ์ก์๋์ธ์. JWT๋ ๊ทธ๋ ๊ฒ ๊ฐ๋จํ์ง ์์์. ์ธ์ ๋๋ ์ฟ ํค๋ฅผ ์ญ์ ํ๊ณ ๊ณ์ํ ์ ์์ต๋๋ค. ์ค์ ๋ก JWT๋ ์ธ์ ๊ณผ ๋ค๋ฅธ ์ฉ๋๋ก ์ฌ์ฉ๋๋ฉฐ ๊ธฐ์กด ํ ํฐ์ ๊ฐ์ ๋ก ์ญ์ ํ๊ฑฐ๋ ๋ฌดํจํํ ์ ์์ต๋๋ค.
JWT ํ ํฐ์ ๊ฐ์ ๋ก ์ญ์ ํ๊ฑฐ๋ ๋ฌดํจํํ ์ ์๋ค๊ณ ํ๋ค...๐ฐ
โ ํ ํฐ์ ํฉ๋ฆฌ์ ์ธ ๋ง๋ฃ ์๊ฐ ์ค์
๋ก๊ทธ์์ ๋์ ํ ํฐ์ ์งง๊ฒ ์ง์ ํ๋ ๋ฐฉ๋ฒ์ด ์์ ๊ฒ์ด๋ค. ๊ทธ๋ฐ๋ฐ ๊ฐ๊ณ๋ถ ์๋น์ค๋ฅผ ์ด์ฉํ๋ ์ ์ ๊ฐ ํ ํฐ ์๊ฐ์ด ์งง์ ์๋น์ค๋ฅผ ์ด์ฉํ ๋๋ง๋ค ๋ก๊ทธ์์์ด ๋๋ค๋ฉด ๋ถํธํ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
โ ๋ก๊ทธ์์ ์ ํด๋ผ์ด์ธํธ ์ธก์์ ์ ์ฅ๋ ํ ํฐ ์ญ์
์ด๊ฑด ํด๋ผ์ด์ธํธ ์ธก์์ ํด์ผ๋๋ ์ผ์ด๋ฏ๋ก ๋ด๊ฐ ํ ์ ์๋ ์ผ์ด ์์ ๊ฒ ๊ฐ๋ค.
๐ก ์์ง ์๊ฐ์ด ๋จ์ ์๋ ๋ ์ด์ ํ์ฑ ํ ํฐ์ด ์๋ DB๋ฅผ ๋ณด์ ํ์ญ์์ค. (๋ฒ์ญ์ด ์ข ์ด์ํ์ง๋ง..)
ํ ํฐ์ db์ ์ ์ฅํ๊ณ ๋ก๊ทธ์์ ์ db์์ ํ ํฐ์ ์ญ์ ํ์ฌ ์๋น์ค ์ด์ฉ์ ์ญ์ ๋ ํ ํฐ์ธ์ง ์๋์ง ํ๋จํ์ฌ ์ญ์ ๋ ํ ํฐ์ผ ์ ์ฌ ๋ก๊ทธ์ธ์ ์๋ํ๋ค.
์ด ๋ฐฉ๋ฒ์ผ๋ก ํ ๋ฒ ํด๋ณด๊ฒ ๋ค!
class Token(models.Model):
token = models.CharField(max_length=100)
user = models.OneToOneField(User, on_delete=models.CASCADE)
class Meta:
db_table = "tokens"
token์ ์ ์ฅํ db๋ฅผ ๋ง๋ค์ด์ค๋ค. ํ user๋ ํ๋์ ํ ํฐ๋ง ๊ฐ์ง ์ ์์ผ๋ฏ๋ก OneToOneField
๋ก user ํ๋๋ฅผ ๊ตฌ์ฑํ์๋ค.
Token.objects.create(user_id=user.id, token=access_token)
๋ก๊ทธ์ธ ์ ๋ฐ๊ธ๋ ํ ํฐ์ db์ ์ ์ฅํด์ค๋ค.
class LogoutView(View):
@log_in_confirm
def post(self, request):
user = request.user
Token.objects.get(user_id=user.id).delete()
return JsonResponse({"message": "LOGOUT_SUCCESS"}, status=200)
์ ์ ๊ฐ logout request๋ฅผ ๋ณด๋์ ์, db์ ์ ์ฅ๋ ํ ํฐ์ ์ญ์ ํ๋ค. ์ฌ๊ธฐ์, log_in_confirm
์ด๋ผ๋ decorator์ ์ฌ์ฉํ์ฌ ๋ก๊ทธ์ธํ ์ ์ ๋ง ์์ฒญ์ ๋ณด๋ผ ์ ์๋๋ก ํ๋ค.
# utils.py
import jwt
from django.http import JsonResponse
from users.models import User, Token
from my_settings import SECRET_KEY, ALGORITHM
def log_in_confirm(func):
def wrapper(self, request, *args, **kwargs):
try:
user_token = request.headers.get("Authorization", None)
user = jwt.decode(user_token, SECRET_KEY, ALGORITHM)
if not User.objects.filter(id=user["id"]).exists():
return JsonResponse({"message": "INVALID_USER"}, status=401)
if not Token.objects.filter(user_id=user["id"]).exists():
return JsonResponse({"message": "INVALID_USER"})
request.user = User.objects.get(id=user["id"])
return func(self, request, *args, **kwargs)
except jwt.InvalidSignatureError:
return JsonResponse({"message": "JWT_SIGNATURE_ERROR"}, status=400)
except jwt.DecodeError:
return JsonResponse({"message": "JWT_DECODE_ERROR"}, status=400)
return wrapper
์๋ log_in_confirm
decorator๊ฐ ๋ค์ด์๋ utils.py
ํ์ผ์ด๋ค. ์ด decorator๋ login์ด ํ์ํ ์๋น์ค๋ฅผ ์ ์ ๊ฐ ์ด์ฉํ ๋, header์ ๋ค์ด์๋ token์ decodeํ์ฌ user์ ์ ๋ณด๋ฅผ ํ๋ํ ๋ค db์์ ์๋ ์ ์ ์ ๋น๊ตํด, ์ค์ ์ ์ ์ธ์ง ํ์ธํ๋ ๊ธฐ๋ฅ์ ํ๋ค.
if not Token.objects.filter(user_id=user["id"]).exists():
return JsonResponse({"message": "INVALID_USER"})
์ ์ฝ๋๊ฐ ๋ด๊ฐ ์๋ก ์ถ๊ฐํ ์ฝ๋์ด๋ค. ๋ง์ฝ decodeํ ํ ํฐ์ ์ ์ ์ ๋ณด์ ํด๋นํ๋ ํ ํฐ์ด token์ ์ ์ฅํ db์ ์๋ค๋ฉด INVALID_USER
์๋ฌ๋ฅผ ๋ฐํํ๋ค.
์ฌ๊ธฐ์ ๋ค์ ์๋น์ค๋ฅผ ์ด์ฉํ๋ ค๋ฉด ์ฌ๋ก๊ทธ์ธ์ ํ๋ฉด token์ด ๋ค์ db์ ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ ์๋น์ค๋ฅผ ์ ์์ ์ผ๋ก ์ด์ฉํ ์ ์๋ค.
์ด๊ฒ ๋ง๋ ๋ฐฉ๋ฒ์ธ์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง! ๋ก๊ทธ์์ ๊ตฌํ ์๋ฃ
<์ฐธ๊ณ >
'Python > ๐ฆ Django' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Django] DRF ์๋ ํ๋ฆ (0) | 2023.11.23 |
---|---|
[Django] ์ฝ๋ฉ ์คํ์ผ (0) | 2023.09.04 |
[Django] Django Custom Command (0) | 2023.09.04 |
[Django] QuerySet ์ดํดํ๊ธฐ - Lazy Loading, Caching, Eager Loading (0) | 2023.09.04 |
[Django] Django ORM์ด๋ ๋ฌด์์ผ๊น? (0) | 2021.10.30 |