STUDY/React
React | JWT 안전하게 저장하기 (localStorage 사용 X) (1)
개미606
2021. 5. 27. 16:50
JWT는 어디에 저장해야 할까
이전 글에서 알아 보았듯, WebStorage(LocalStorage 혹은 SessionStorage)
에 저장하면 안 된다!
그러다가 이 가이드를 발견했고, 이대로 따라해보기로 했다.
가이드는 아래와 같은 방식으로 구현된다.
- 서버는
GraphQL
이다. http통신으로JWT
를 받는다. LocalStorage
에JWT
를 저장하지 않는다. (중요)JWT
는In Memory
에 저장한다. -> 이 가이드는 in memory방식의 문제점을 해결해준다..! (매우 중요)- 서버에서
refresh_token
을 제공해야 한다. (제일 중요) - 탭을 새로 생성해도, 다른 탭에서 로그아웃을 해도 정상적으로 처리되도록 만든다!
그리고 이 가이드와 내가 한 방식의 다른점..!
- 서버가 없음 -> 서버까지 구현하기 귀찮았다..😥 -> http 통신은 생략한다!
- 만약 access_token과 refresh_token을 반환하는 인증 처리를 하고싶다면...? 이 글부터 쭉 따라해보세요^^
React
를 사용할 것임 -> 그리고useReducer
hook도 사용한다 - 이건 자유.. 쓰고싶은대로 쓰면 된다 사실..
React 프로젝트 생성
create-react-app
을 이용한다.
$ create-react-app jwt-inmemory-test
그리고 필요한.. 모듈을 install한다. 일단 리액트 라우터를 사용하기 위해..
$ npm install react-router-dom
컴포넌트들 생성
만들고 싶은 대로 만든다..
Login.jsx
: 로그인 하는 페이지Home.jsx
: 로그인을 하지 않아도 접근할 수 있는 페이지Hello.jsx
: 로그인을 해야만 접근할 수 있는 페이지
auth.js 작성
만들고 싶은 위치에 auth.js
파일을 생성한다.
이 파일 내에 인증관련된 메서드들을 작성할 것이다!
일단 login
메서드를 만든다. id와 password를 받아 일치하면 멋진.. 토큰을 반환한다.
export function login({ id, password }) {
if (id === 'russ' && password === 'whynot0') {
return {
access_token: 'jx84e3kjew1njej3al2q9w',
refresh_token: 'g2rjfd7452bjfgn;a&*(jkehj',
};
} else {
return undefined;
}
}
App.js에서 useReducer로 인증 접근 처리
나는 PrivateRoute
를 만들어서 처리했는데, 그냥 state값으로 바로 처리해도 될 것 같다.
initialState
는 말그대로 기본 state다.authenticated
값은 인증 여부를 boolean
값으로 담고, token
에는 인증 후 받은 토큰을 저장할 곳이다.
const initialState = {
authenticated: false,
token: null
}
reducer
도 작성해준다. SET_TOKEN
이라는 type을 가진 dispatch
가 실행되면, state를 변경한다.
function reducer(state, action) => {
switch(action.type) {
case 'SET_TOKEN':
return {...state, token: action.token, authenticated: action.result};
default:
return state;
}
}
App.js
를 마저 작성하면.. 이렇다.handleLogin
메서드를 Login
컴포넌트에 props로 전달한다.
// 이 부분에 initailState와 reducer를 작성
function App() {
const [state, dispatch] = useReducer(reducer, initialState);
const { authenticated } = state;
function handleLogin(id, password) {
let token = auth.login(id, password);
if (token) {
console.log('로그인 성공!');
dispatch({
type: 'SET_TOKEN',
token: token,
result: true,
});
} else {
console.log('로그인 실패');
dispatch({
type: 'SET_TOKEN',
token: null,
result: false,
});
}
}
return (
<Router>
<Switch>
<Route exact path="/" render={Home} />
<PublicRoute
path="/login"
authenticated={authenticated}
compoenent={(props) => <Login {...props} handleLogin={handleLogin} />}
/>
<PrivateRoute
path="/hello"
authenticated={authenticated}
component={(props) => (
<Hello {...props} />
)}
/>
</Switch>
</Router>
);
}
export default App;
갑자기 힘들어져서 다음에 이어서...