JWT claim custumizing
serializer를 활용하여 simplejwt에서 제공하는 기본 정보 이외에 포함하고 싶은 정보를 payload에 추가적으로 넣을 수 있다.
1) user/jwt_claim_serializer.py 파일 생성 후 작성
# TokenObtainPairSerializer를 임포트해서 새로생성할 serializer에 상속 시켜줘야한다.
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
# TokenObtainPairSerializer를 상속하여 클레임 설정
class SpartaTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user): # request 했을때 들어오는 user
# 가져온 user정보로 token 생성
token = super().get_token(user)
# 토큰에 추가할 필드 설정하기.
token['id'] = user.id
token['username'] = user.username
return token
2) serializer를 실행할 view를 user/views.py 에 추가
from user.jwt_claim_serializer import SpartaTokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
...
class SpartaTokenObtainPairView(TokenObtainPairView):
serializer_class = SpartaTokenObtainPairSerializer
* simplejwt 에서 제공하는 TokenObtainPairView의 serializer_class 변수에 커스텀한 시리얼라이저를 넣어주는 것.
3) 생성한 view를 실행할 urls path 추가
user/urls.py
from user.views import SpartaTokenObtainPairView
...
urlpatterns = [
...
path('api/sparta/token/', SpartaTokenObtainPairView.as_view(), name='sparta_token'),
]
포스트맨에서 해당 url로 토큰을 발급받아 https://jwt.io/ 에서 확인해보면 payload에 username이 추가된 것을 볼 수 있다.
프론트엔드에서 JWT 테스트
로그인 => 유저데이터 받아서 서버에 요청
// 로그인 함수. es6문법
const onLogin = (e)=>{
// requestAccessToken 함수 비동기통신을 위해 async fetch 사용
const requestAccessToken = async (url, sendData)=>{
const response = await fetch(url, {
headers: { // 헤더에 담을 데이터 방식
'Content-Type': 'application/json',
},
method: "POST",
body: JSON.stringify(sendData) // sendData = loginInfo
});
return response.json();
};
const data = new FormData(e);
const loginInfo = {
"username": data.get("username"),
"password": data.get("password")
};
// then : 요청 후에 응답한 결과, data : 서버가 클라이언트에게 준 응답
requestAccessToken("/user/api/token/", loginInfo).then((data=>{
const accessToken = data.access;
const refreshToken = data.refresh;
document.querySelector("#access-token").value = accessToken;
document.querySelector("#refresh-token").value = refreshToken;
// 서버로 부터 응답받은 accessToken과 refreshToken, payload를 클라이언트 저장소에 저장
localStorage.setItem("sparta_access_token", accessToken);
localStorage.setItem("sparta_refresh_token", refreshToken);
// access token에서 payload를 꺼내는 작업
// 0 -> header, 1 -> payload, 2 -> VERIFY SIGNATURE
const base64Url = accessToken.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
document.querySelector("#payload").value = jsonPayload;
localStorage.setItem("payload", jsonPayload);
}));
return false;
};
LocalStorage
- 브라우저 내에 존재하는 저장소.
- 웹 브라우저가 종료되면 사라지는 `SessionStorage` 와는 다르게 브라우저가 종료되어도 저장된 정보가 계속 남아있는 공간이다.
- 데이터는 `key-value` 로 저장된다.
- 서버로 부터 응답받은 JWT 정보를 `localStorage` 에 넣어놓고 인가를 필요로 하는 요청을 할 때 `access` 토큰을 `header` 에 담아서 전달하는 방식이다.
// localStorage에 데이터 쓰기
localStorage.setItem("item_key", value);
// localStorage에서 데이터 읽기
localStorage.getItem("item_key");
// localStorage에 키에 맞는 데이터 삭제
localStorage.removeItem("item_key");
// localStorage에 있는 모든 데이터 삭제
localStorage.clear();
// localStorage에 있는 모든 데이터(Key Value 쌍)의 개수
localStorage.length;
Refresh token 이용해서 새로운access token 받기
// 페이지를 다시 로딩 됐을 때
window.onload = ()=>{
// localstorage에서 payload를 꺼내온다.
const payload = JSON.parse(localStorage.getItem("payload"));
// exp : 토큰 인증유효시간
// 아직 access 토큰의 인가 유효시간이 남은 경우
if (payload.exp > (Date.now() / 1000)){
document.querySelector("#loginForm").setAttribute("style", "display:none");
document.querySelector("#access-token").value = localStorage.getItem("sparta_access_token");
document.querySelector("#refresh-token").value = localStorage.getItem("sparta_refresh_token");
document.querySelector("#payload").value = JSON.stringify(localStorage.getItem("payload"));
} else {
// 인증 시간이 지났기 때문에 다시 refreshToken으로 다시 요청을 해야 한다.
const requestRefreshToken = async (url) => {
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
},
method: "POST",
// body에 refresh token 을 넣어서 재요청
body: JSON.stringify({
"refresh": localStorage.getItem("sparta_refresh_token")
})}
);
return response.json();
};
// 다시 인증 받은 accessToken을 localStorage에 저장하자.
requestRefreshToken("/user/api/token/refresh/").then((data)=>{
// 새롭게 발급 받은 accessToken을 localStorage에 저장
const accessToken = data.access;
document.querySelector("#access-token").value = accessToken;
// 받은 토큰 다시 localstorage에 저장한다.
localStorage.setItem("sparta_access_token", accessToken);
document.querySelector("#refresh-token").value = localStorage.getItem("sparta_refresh_token");
document.querySelector("#payload").value = JSON.stringify(localStorage.getItem("payload"));
document.querySelector("#loginForm").setAttribute("style", "display:none");
});
}
};
인가된 사용자의 요청
// 인가된 사용자 요청
const onRequestButtonClick = () => {
const requestAuthData = async () => {
const response = await fetch("/user/api/authonly/", {
method:"GET",
headers: { // 헤더에 토큰을 담아서 보낸다.
'Content-Type': 'application/json',
"Authorization": "Bearer " +localStorage.getItem("sparta_access_token")
},
});
return response.json();
}
requestAuthData().then((data)=>{
document.querySelector("#auth-only").value = data.message;
})
};
'AI 웹 개발 과정 > DRF 특강' 카테고리의 다른 글
django-dotenv (0) | 2022.07.30 |
---|---|
DRF JWT 사용하기 (1) | 2022.07.27 |
DRF 테스트 코드 작성하기 1 (0) | 2022.07.11 |
DRF 를 이용한 JWT 사용하기 (0) | 2022.06.27 |
DRF 퀴즈2 (0) | 2022.06.24 |