DRF(Django Rest Framework)(7) _ 회원가입 기능(Front-End)
01. 회원가입 기능 만들기
- 이제 Front-End 부분까지 연결하여 회원가입 기능을 완성해보려 한다.
- 아래 window.onload는 자바스크립트가 제대로 참조되어 시행되었는지 검사(F12)창의 콘솔에서 확인하고자 할 때 유용하게 사용할 수 있다.
window.onload = ()=>{
console.log("로딩되었음")
}
- 아래와 같이 인덱스 페이지를 만들고 자바스크립트를 활용하여 회원가입시 입력된 내용을 POST 해보려한다.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Signup</title>
<script src="api.js"></script>
</head>
<body>
<h1>회원가입 페이지</h1>
<form>
<input type="email" name="email" id="email" placeholder="email">
<input type="password" name="password" id="password" placeholder="password">
<button type="button" onclick="handleSignin()">제출</button>
</form>
</body>
</html>
- 자바스크립트는 api.js로 만들고 아래와 같이 코드를 짰다.
window.onload는 api.js가 정상적으로 로드되었는지 콘솔창에서 확인하기 위함이고,
async 이후는 email과 password를 각 input에서 value를 받아와서 const로 지정된 변수에 담아넣고, console에 확인하기 위해 log를 찍어준 부분이다.
아래 const response 부분은 fetch된 부분이 모두 로드될 때까지 기다리고, POST 요청이 왔을 때 headers의 속성으로 body에 값을 넣어 response에 할당한다. 이때 body는 Json형식으로 입력되는데 string으로 바꾸어주기 위해 JSON.stringify 처리 해준다.
// api.js
window.onload = ()=>{
console.log("로딩되었음")
}
async function handleSignin(){
const email = document.getElementById("email").value
const password = document.getElementById("password").value
console.log(email, password)
const response = await fetch('http://127.0.0.1:8000/users/signup/', {
headers:{
'content-type' : 'application/json',
},
method:'POST',
body:JSON.stringify({
"email":email,
"password":password
})
})
console.log(response)
}
- 그러나 현재까지 진행된 부분을 실행해보면 콘솔창에서 아래와 같은 오류를 확인할 수 있다.
- 잘 확인해보면 이전에 다루었던 CORS 문제인 것 같다. (※ 참고 링크)
*CORS : Origin(주소와 포트)이 다를 경우 보안을 위해 Access 허용을 받도록 하는 것
django-cors-headers를 설치하고,
pip install django-cors-headers
아래 내용을 settings.py에 추가해준다.
# settings.py
INSTALLED_APPS = [
...,
"corsheaders",
...,
]
MIDDLEWARE = [
...,
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
...,
]
CORS_ALLOW_ALL_ORIGINS = True
- 수정을 한 뒤에는 다시 서버를 켜주고, email, password를 입력 후 제출하면 아래와 같이 정보를 확인할 수 있다.
db에서도 정상적으로 회원등록되어있음을 확인할 수 있다.
02. 로그인 기능 만들기
- 이미 만들어진 회원가입 페이지를 활용하여 간단하게 로그인 페이지를 아래와 같이 만들었다.
타이틀과 내용을 변경하고, 버튼의 onclick부분을 handleLogin으로 이름을 변경하였다.
<!-- login.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<script src="api.js"></script>
</head>
<body>
<h1>로그인 페이지</h1>
<form>
<input type="email" name="email" id="email" placeholder="email">
<input type="password" name="password" id="password" placeholder="password">
<button type="button" onclick="handleLogin()">제출</button>
</form>
</body>
</html>
- 이제 api.js 파일에 아까 지정한 handleLogin을 추가해주어야 한다.
마찬가지로 handleSignin()과 대부분 유사한 로직으로 동일하게 작성될 수 있어 가져왔지만, fetch 주소는 'http://127.0.0.1:8000/users/api/token/' 으로 변경해준다. (*django user app의 urls.py 참고)
// api.js
async function handleLogin(){
const email = document.getElementById("email").value
const password = document.getElementById("password").value
console.log(email, password)
const response = await fetch('http://127.0.0.1:8000/users/api/token/', {
headers:{
'content-type' : 'application/json',
},
method:'POST',
body:JSON.stringify({
"email":email,
"password":password
})
})
console.log(response)
- 로그인 페이지에서도 정상적으로 읽어오고 있다. 그런데 우리는 토큰값을 알고 싶다.
- 위의 코드에서 아랫줄에 'const response_json = await response.json()'를 추가해주고, 콘솔에 나타내기 위해console.log(response_json)로 변경해주면 토큰값을 읽어올 수 있게된다.
async function handleLogin(){
const email = document.getElementById("email").value
const password = document.getElementById("password").value
console.log(email, password)
const response = await fetch('http://127.0.0.1:8000/users/api/token/', {
headers:{
'content-type' : 'application/json',
},
method:'POST',
body:JSON.stringify({
"email":email,
"password":password
})
})
const response_json = await response.json()
console.log(response_json)
}
- 이제 토큰까지 잘 불러왔으니 불렁온 내용을 Local Storage에 저장하도록 한다. 현재는 검사(F12)창의 Application에 들어가보면 local storage에는 key, value가 아무것도 없음을 볼 수 있다.
- local storage에 값을 저장하기 위해서는 localStorage.setItem("key", value값) 형식으로 저장할 수 있다.
access와 refresh를 각각 저장하기 위해 아래와 같이 추가해준다.
// api.js
async function handleLogin(){
...
localStorage.setItem("access", response_json.access);
localStorage.setItem("refresh", response_json.refresh);
}
- 당연하다는 듯이 잘 저장되어 나타나는 것을 확인할 수 있다.
- jwt에 들어가면 확인할 수 있는 payload 값도 local storage에 저장하고 싶을 때에는 아래 코드를 추가해준다.
async function handleLogin(){
...
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)
}
- payload도 정상적으로 local storage에 저장하였다.
03. 로그인 후 사용자 정보 인덱스 페이지에 로드하기
- 기존에 index.html에 있던 내용은 회원가입 기능이므로 signup.html을 생성하여 코드를 옮겨주었다.
index.html과 index.js에는 아래와 같이 작성했다.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>홈페이지</title>
<script src="index.js"></script>
</head>
<body>
<h1>홈페이지</h1>
<div id="intro"></div>
</body>
</html>
- index.js 파일에서는 앞서 가져왔던 payload를 받아와 const로 저장 후 console.log로 출력해본다.
// index.js
console.log("로딩되었습니다.")
window.onload = ()=>{
const payload = localStorage.getItem("payload");
console.log(payload)
}
- 위와 같이 작성 후 인덱스 페이지를 로드하면 아래와 같이 확인할 수 있다.
- 하지만 이 상태에서는 특정 value를 바로 가져올 수 없다. payload 변수를 JSON.parse를 통해 처리하여 payload_parse라는 변수를 만들어주고, 출력해보면 JSON으로 분리된 것을 확인할 수 있다.
// index.js
console.log("로딩되었습니다.")
window.onload = ()=>{
const payload = localStorage.getItem("payload");
const payload_parse = JSON.parse(payload)
console.log(payload_parse)
}
- 이제 특정 value를 꺼내올 수 있다.
// index.js
console.log("로딩되었습니다.")
window.onload = ()=>{
const payload = localStorage.getItem("payload");
const payload_parse = JSON.parse(payload)
console.log(payload_parse.email)
}
04. 가져온 사용자 정보를 화면에 띄우기
- 홈페이지에 intro라는 id를 가진 div를 만들었었다. 이를 활용하여 javascript에서 정보를 가져와 intro에 띄울 예정이다.
아래 코드처럼 const intro를 만들고, document.getElementById("intro")를 통해 html파일에서 intro를 연결한다. 이 때 document는 html 파일을 지칭한다. 그 후 innerText를 사용하여 payload_parse.email을 할당하여 intro에 넣는다.
// index.js
console.log("로딩되었습니다.")
window.onload = ()=>{
const payload = localStorage.getItem("payload");
const payload_parse = JSON.parse(payload)
console.log(payload_parse.email)
const intro = document.getElementById("intro")
intro.innerText = payload_parse.email
}
05. 가져온 사용자 정보를 화면에 띄우기
- users 앱의 views.py에 아래와 같이 mockView를 만들어준다.
# users/views.py
class mockView(APIView):
permission_classes = [permissions.IsAuthenticated]
def get(self, request):
user = request.user
user.is_admin = True
user.save()
return Response("get 요청")
- mock api기능을 적용하기 위해 로그인 화면에 아래와 같이 mock버튼을 추가한다.
<!-- login.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<script src="api.js"></script>
</head>
<body>
<h1>로그인 페이지</h1>
<form>
<input type="email" name="email" id="email" placeholder="email">
<input type="password" name="password" id="password" placeholder="password">
<button type="button" onclick="handleLogin()">제출</button>
</form>
<button type="button" onclick="handleMock()">모크 api</button>
</body>
</html>
- api.js파일에는 handleMock 함수를 아래와 같이 만들어준다. 위에서 정의한 mockView를 참고한다. (GET)
// api.js
async function handleMock(){
const response = await fetch('http://127.0.0.1:8000/users/mock/', {
headers:{
"Authorization":"Bearer " + localStorage.getItem("access")
},
method: 'GET',
})
console.log(response)
}
- 로그인 페이지에서 로그인(제출 버튼)을 하고 모크 api 버튼을 클릭하면 콘솔창에서 토큰을 확인할 수 있다.
06. 로그아웃 기능 구현하기
- 로그아웃은 local storage에 있는 사용자 정보(access, refresh, payload)를 지워주는 개념이다.
- 먼저 템플릿의 맨 아래쪽에 동작시킬 logout 버튼을 만들어준다.
<!-- login.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<script src="api.js"></script>
</head>
<body>
<h1>로그인 페이지</h1>
<form>
<input type="email" name="email" id="email" placeholder="email">
<input type="password" name="password" id="password" placeholder="password">
<button type="button" onclick="handleLogin()">제출</button>
</form>
<button type="button" onclick="handleMock()">모크 api</button>
<button type="button" onclick="handleLogout()">로그아웃</button>
</body>
</html>
- api.js 파일에는 logout 기능을 구현할 코드를 짜주면 된다. 로컬 스토리지에 저장된 정보를 삭제할 때에는 localStorage.removeItem("<삭제할 key명>")를 사용한다.
// api.js
...
async function handleLogout(){
localStorage.removeItem("access")
localStorage.removeItem("refresh")
localStorage.removeItem("payload")
}
※ removeItem 대신에 clear()로 간단히 사용도 가능하다.
async function handleLogout(){
localStorage.clear();
}
'DEV > Web 개발' 카테고리의 다른 글
Web 개발 :: 파이썬 Django Rest Framework(8) _ 게시글 생성 (0) | 2022.11.01 |
---|---|
Web 개발 :: django, get_object_or_404, get_list_or_404_TIL#41 (0) | 2022.10.31 |
Web 개발 :: 파이썬 Django Rest Framework(6) _ token, permission (0) | 2022.10.30 |
파이썬/머신러닝 웹 프로그래밍 :: 10월 다섯째주 WIL #09 (0) | 2022.10.29 |
Web 개발 :: 파이썬 Django Rest Framework(5) _ CustomUser 등록 및 회원가입 (1) | 2022.10.29 |
댓글