회원가입과 로그인을 만들었으니 로그아웃을 구현한다. 로그아웃의 기능은 간단하다. 유저 인증을 프론트에서 보낸 JWT토큰을 통해 인증하는 방식으로 진행하고 있으므로, 먼저 db에 있는 JWT 토큰을 파기하여 유저 인증 절차가 불가능하게 만들어주면 된다. 그 후 Redux를 통해 사용한 LocalStorage(또는 SessionStorage)를 비워주고, 혹시 모르니 브라우저 쿠키도 파기해준다. Redux는 새로고침하면 사라지기 때문에 굳이 지워주지 않아도 되는데, 그냥 연습용으로 dispatch 한번 더 불러와 사용해본다. 모든 절차가 완료되면 새로고침 코드를 적용하여 페이지를 정돈해준다. 새로고침을 하면 모든 컴포넌트가 다시 마운트되기 때문에, 유저가 새로고침 할 필요 없이 메인 페이지가 바뀌는 모습을 볼 수 있다.
.
Frontend
Topbar 컴포넌트를 두개 만들고, 로그인 전에는 로그인과 회원가입이 보이는 Topbar를, 로그인 후에는 유저 닉네임이 보이는 Topbar를 만든다. 이후 Combiner.js에서 두개의 컴포넌트를 합쳐준다. 유저 정보는 굳이 redux를 사용해도 되고, props로 전송해도 된다. 나는 다양한 기능을 사용해보는게 목적이라 props를 사용했다. 자식 컴포넌트에 작명={props로보내줄변수} 를 입력하면, 프롭스를 통해 데이터를 전달해줄 수 있다.
App.js
const [isAuth, setAuth] = useState(false)
useEffect( ()=>{
// 현재 user상태를 가져온다.
axios.post('/api/user/auth',body)
.then(response => {
console.log('App.js => auth정보',response.data)
// 만일 로그인 된 상태면
if(response.data.isAuth === true){
console.log('리스폰스 데이터',response.data)
// Redux에 쿠키에 저장된 토큰을 받아와 할당하라
dispatch(GET_TOKEN(cookies.get('w_auth')))
// res로 받아온 정보를 GET_USER에 할당하라
dispatch(GET_USER({email:response.data.email, name:response.data.name, nikname:response.data.nikname, role:response.data.role}))
//<==========추가한 부분===========>
// state에 값을 할당한다.
setAuth(true)
//<================================>
}
else {
// 만일 유저가 없으면(로그인하지 않은 상태라면)
}
})
},[])
return (
<div>
<Combinebar isAuth={isAuth} userNikname={userNikname}></Combinebar>
...
</div>
)
export default App;
Combinebar.js
Topbar는 로그인한 상태에서 보여줄 컴포넌트이고, TopbarLogout은 로그인하지 않은 상태에서 보여줄 컴포넌트이다. 로그인 한 상태에서 유저의 정보를 보여주어야 하기 때문에, Topbar.js에게만 props를 전달해 주었다. props로 App.js에서 수행한 auth Api 요청의 결과물 isAuth를 받아와, 유저가 로그인 한 경우와 그렇지 않은 경우를 구분할 수 있도록 해 주었다.
function Combinebar(props) {
let isAuth = props.isAuth
if (isAuth===true) {
return(
<div>
<Topbar userNikname={props.userNikname}></Topbar>
<hr style={{margin:0, color:'#a7aaad'}}/>
<NavList userNikname={props.userNikname}></NavList>
</div>
) } else {
return (
<div>
<TopbarLogout></TopbarLogout>
<hr style={{margin:0, color:'#a7aaad'}} />
<NavList userNikname={props.userNikname}></NavList>
</div>
)
}
}
export default Combinebar;
이제 로그아웃 api를 호출할 Topbar를 작성한다. Topbar에서 로그아웃 이라는 버튼을 클릭하면 유저가 로그아웃되게 할 것이다.
로그아웃 버튼을 누르면 백엔드로 DB속에 들어있는 토큰을 파기해달라는 요청을 보낸다. 백엔드가 성공적으로 일을 마치고 돌아오면, 프론트는 브라우저에 저장해두었던 여러 정보를 정리해 줄 것이다. 리액트에서 쿠키와 세션스토리지를 이용하려면 먼저 해당 스토리지를 불러오는 절차가 필요하다. 세션 스토리지는 window.sessionStorage로 불러오고, 쿠키를 지우는 함수는 아래와 똑같이 작성해주면 된다.
//세션스토리지를 불러오는 함수 let sessionStorage = window.sessionStorage; //쿠키를 지우는 함수 let deleteCookie = function(name) { document.cookie = name + '=; expires=Thu, 01 Jan 1999 00:00:10 GMT;'; } |
Topbar.js
가장 하단에 location.reload()를 주석과 함께 첨부해주면, 로그아웃 버튼을 눌렀을 때 api요청을 완료한 뒤 페이지를 한번 새로고침한다. if문을 활용하여 api요청이 성공했을 경우에만 쿠키와 세션 등을 삭제하고, 요청이 아예 실패했을 때는 데이터가 유지되도록 alert 알림창만 띄운다.
let sessionStorage = window.sessionStorage;
let deleteCookie = function(name) {
document.cookie = name + '=; expires=Thu, 01 Jan 1999 00:00:10 GMT;';
}
function logout(){
axios.get('/api/user/logout')
.then(response => {
if (response.data.success) {
console.log(response)
// 쿠키 삭제
deleteCookie('w_authExp')
deleteCookie('w_auth')
// 세션 삭제
sessionStorage.clear()
// Redux 정보 삭제
dispatch(DELETE_TOKEN);
dispatch(DELETE_USER)
// localStroage 정보 삭제
localStorage.clear()
//새로고침
// eslint-disable-next-line no-restricted-globals
location.reload()
} else {
alert('로그아웃에 실패하였습니다.')
}
})}
Backend
api/user/logout이 하는 역할은 다음과 같다.
api 요청한 유저의 정보를 DB에서 찾아내기 -> 해당 유저의 JWT 토큰 삭제하기 -> 프론트로 성공 메세지 전달하기 |
여기서 'api 요청한 유저의 정보를 DB에서 찾아내기' 항목은 이전시간에 만든 auth가 수행하기 때문에, auth를 불러와 주기만 하면 된다. auth는 user 속에 찾아낸 유저의 데이터를 담아 반환한다고 했다. 따라서 auth가 반환한 유저 정보를 활용하여, 몽구스에 포함된 findOneAndUpdate 함수로 해당 유저의 토큰들을 NULL값으로 만들어주면 된다. findOneAndUpdate는 첫번째 인자로 전달받은 데이터를 이용해 DB에서 find를 실행하고, 찾아낸 doc의 지정된 항목을 수정(Update)해준다.
server/routes/users.js
router.post("/logout", auth, (req, res) => {
// middleware의 auth.js에서 _id를 가져와 해당하는 유저의 토큰을 삭제한다.
User.findOneAndUpdate({ _id: req.user._id }, { token: "", tokenExp: "" }, (err, doc) => {
if (err) return res.json({ success: false, err });
return res.status(200).send({
success: true
});
});
});
콘솔창
'프로젝트 > 풀스택 프로젝트' 카테고리의 다른 글
4-6. [React + Node.js Express] 프로필 사진 업로드 (1) | 2022.12.10 |
---|---|
4-5. [React + Node.js Express] 회원 정보 수정 기능 (0) | 2022.12.06 |
4-3. [React + Node.js Express] 유저 인증 기능 (1) | 2022.12.05 |
4-2. [React + Node.js Express] 로그인 기능 (0) | 2022.12.03 |
4-1. [React + Node.js Express] 회원가입 기능 (0) | 2022.12.02 |
댓글