CORS (Cross-origin resource sharing 교차 출처 리소스 공유)
FE에서 BE로 request를 줄 때 CORS 설정을 해야한다 그렇지 않으면 통신이 되지않는다.
1. CORS 패키지 설치
pip install django-cors-headers
2. settings.py 코드 작성
INSTALLED_APPS = [
...
'rest_framework',
'corsheaders',
...
]
MIDDLEWARE = [
...
"corsheaders.middleware.CorsMiddleware", # 아래의 코드보다 무조건 위에 적어야함
"django.middleware.common.CommonMiddleware",
...
]
# FE의 주소값을 입력해주어야한다.
CORS_ALLOWED_ORIGINS = [
"http://localhost:5500",
"http://127.0.0.1:5500",
]
json데이터로 보낼 때는 headers 를 만들어 json으로 보내 주는 것을 명시 해야한다. 그렇지 않으면 415 오류가 발생한다.

회원가입 javascript
async function join() {
// 입력받은 데이터 가져오기
const joinData = {
email: document.getElementById("input-id-join").value,
fullname: document.getElementById("input-fullname-join").value,
password: document.getElementById("input-password-join").value,
password_confirm: document.getElementById("input-password-confirm").value,
}
// 입력받은 데이터를 BE서버에 회원가입 url로 request 요청
const response = await fetch(`${backend_base_url}/user/`, {
// headers를 통해 json 데이터임을 알려줘야 415 오류가 발생하지않는다.
headers: {
Accept: "application/json",
'Content-type': "application/json"
},
method: "POST",
body: JSON.stringify(joinData)
})
// response 받은 내용을 json 화
respose_json = await response.json()
// 정상적인 통신이 되었을 경우 = 회원가입 완료 > 로그인페이지로
if (response.status == 201) {
alert("회원가입 완료!")
window.location.replace(`${frontend_base_url}/templates/user/login.html`);
} else {
alert(response.status)
}
}
DRF - simple JWT
1. pip install
pip install djangorestframework-simplejwt
2. settings.py - 다른건 다몰라도 꼭 settings.py에 코드를 추가해야지만 정상적으로 BE views.py에서 request.user 를 통해 로그인유저에 대해서 데이터를 가져 올 수 있게된다.
INSTALLED_APP = [
...
'rest_framework_simplejwt',
...
]
...
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': [ # session 혹은 token을 인증 할 클래스 설정
'rest_framework_simplejwt.authentication.JWTAuthentication',
...
],
...
}
# JWT 관련 세부 설정 (생략 가능)
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': False,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'JWK_URL': None,
'LEEWAY': 0,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
3. urls.py - 이미 생성 되어있는 클래스들을 import 해와서 url에 지정해줘서 사용함
# user/urls.py
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
# 토큰 유효성 검사용
from user.views import OnlyAuthenticatedUserView
# user/
urlpatterns = [
path('', views.UserAPIView.as_view()),
path('api/token/', TokenObtainPairView.as_view(), name="token_obtain_pair"),
path('api/token/refresh/', TokenRefreshView.as_view(), name="token_refresh"),
# 토큰 유효성 검사용
path('api/authonly/', OnlyAuthenticatedUserView.as_view()),
]
4. views.py - 로그인 정보 확인용
#user/views.py
from rest_framework_simplejwt.authentication import JWTAuthentication
# user/
class UserAPIView(APIView):
# JWT 인증방식 클래스 지정하기
authentication_classes = [JWTAuthentication]
# 로그인 한 유저 정보 출력
def get(self, request):
user = UserModel.objects.get(id=request.user.id)
return Response(UserSerializer(user).data, status=status.HTTP_200_OK)
5.0 javascript 작성 전 중복 코드 방지하기 위해 _base.js 작성해서 html에 우선 include 해오기
// _base.js
// For All
const backend_base_url = "http://127.0.0.1:8000"
const frontend_base_url = "http://127.0.0.1:5500"
5. jwt 로그인 구현 (FE - javascript)
// user.js
async function login() {
const loginData = {
email: document.getElementById("input-id-init").value,
password: document.getElementById("input-password-init").value,
}
const response = await fetch(`${backend_base_url}/user/api/token/`, {
headers: {
Accept: "application/json",
'Content-type': "application/json"
},
method: "POST",
body: JSON.stringify(loginData)
})
response_json = await response.json()
if (response.status == 200) {
// 로컬스토리지에 jwt access 토큰과 refresh 토큰 저장
localStorage.setItem("access", response_json.access)
localStorage.setItem("refresh", response_json.refresh)
// 파싱하는 부분 복사해서 사용하기!
const base64Url = response_json.access.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(''));
localStorage.setItem("payload", jsonPayload);
// window.location.replace(`${frontend_base_url}/`);
alert("환영합니다!")
window.location.replace(`${frontend_base_url}/templates/art/main.html`);
} else {
alert(response.status)
}
}
6. auth.js - 발급 받은 토큰 자동 refresh, 토큰 없을 경우 로그인창으로 돌려보내기
// auth.js
window.onload = ()=>{
// 로컬스토리지에 저장되어있는 payload 가져오기
const payload = JSON.parse(localStorage.getItem("payload"));
// payload 정보 없을 경우 = 로그인 하지않음
if (payload == null){
window.location.replace(`${frontend_base_url}/templates/user/login.html`);
}
// 아직 access 토큰의 인가 유효시간이 남은 경우
if (payload.exp > (Date.now() / 1000)){
} else {
// 인증 시간이 지났기 때문에 다시 refreshToken으로 다시 요청을 해야 한다.
// refresh 토큰으로 access 토큰 얻어오는 코드 작성
const requestRefreshToken = async (url) => {
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
},
method: "POST",
body: JSON.stringify({
"refresh": localStorage.getItem("refresh")
})}
);
return response.json();
};
// 위애서 작성한 함수에 url넣어 작동시켜 refresh 받은 accessToken을 localStorage에 저장
requestRefreshToken(`${backend_base_url}/user/api/token/refresh/`).then((data)=>{
// 새롭게 발급 받은 accessToken을 localStorage에 저장
const accessToken = data.access;
localStorage.setItem("access", accessToken);
});
}
};
7. 로그인되어있는지 안되어있는지 검증은 위에서 만든 js 들을 순서대로 임포트해오기만 하면 끝
<!-- JS import -->
<script src="/static/js/_base.js"></script>
<script src="/static/js/auth.js"></script>
7.1 로그인된 유저의 정보를 가져와 사용하려면 fetch api 요청 시 headers에 Authorization 을 통해 access토큰을 보내 줘야만 한다. "Bearer " 를 꼭 붙여줘야한다.(세팅 때 변경 할 수 있으나 관용적으로 쓰인다.)
// 비동기 통신 async 내가 가진 상품 리스트 출력
async function getMyGalleryList() {
const response = await fetch(`${backend_base_url}/mygallery/`, {
headers: {
Accept: "application/json",
'content-type': "application/json",
"Authorization": "Bearer " + localStorage.getItem("access")
},
method: 'GET',
// body: JSON.stringify(Data)
})
response_json = await response.json()
'회고록(TIL&WIL)' 카테고리의 다른 글
TIL 2022.07.07 javascript fetch api, 이미지 미리보기, radio 값가져오기, 날짜포맷팅, forEach문, arrow function, modal (0) | 2022.07.06 |
---|---|
WIL 2022.07.06 SMOPS 유화제작 팀프로젝트 - S.A & KPT (0) | 2022.07.06 |
TIL 2022.06.25 DRF/ 아침 숙제 풀이 (0) | 2022.06.25 |
TIL 2022.06.24 DRF/ User관련 구현, Article관련 구현, 특강 숙제 (0) | 2022.06.24 |
TIL 2022.06.23 머신러닝 특강 (0) | 2022.06.23 |