React 블로그 - 로그인 구현

https://electricburglar.tistory.com/155

React로 블로그 만들기 #8

- 로그인 구현(5) 새로고침 후 로그인 유지 -

1. 로그인 유지

- 로그인을 한다고 해도 자동으로 로그인 상태가 유지되지 않는다. - 브라우저를 닫거나 새로고침할 시 스토어 값이 초기화되므로 페이지에 다시 들어왔을 때 로그인을 유지하는 로직이 필요하다.

- TodoApp에서는 쿠키를 이용하여 로그인을 유지하였지만, 블로그 앱에서는 HTML5에서 제공하는Web Storage API를 사용한다.

- 또한 로그아웃 시 소셜로그인으로 발급받은 토큰을 제거하도록 로직을 추가해야함.

2. localStorage vs sessionStorage

- Key와 Value 값으로 저장.

- 문자열이 아닌 객체도 저장이 가능하며 5MB까지 저장 가능함.

- 쿠키와 다르게 만료기간을 지정할 수 없으며, 서버로 전송되지 않음.

- 자동로그인을 원하면 localStorage를 사용하고 브라우저를 닫으면 로그인이 풀리는 것을 원하면 sessionStorage를 사용

1) localStorage

- 사용자가 지우지 않는 이상 영구적으로 계속 브라우저에 남아있음.

- 따라서 지속적으로 필요한 정보를 저장한다. (자동로그인 등)

2) sessionStorage

- 윈도우나 브라우저를 닫는 경우 사라지며 뿐만 아니라 브라우저 내에서 탭을 생성하는 경우에도 별도의 영역으로 할당됨.

- 잠시동안 필요한 정보를 저장한다. (일회성 로그인 등)

3. 구현하기

1) src/Components/Login.js

- 소셜로그인 성공 시 받은 정보를 세션스토리지에 저장함.

import React, { Component } from 'react';
import { GoogleLogin } from 'react-google-login';
import KakaoLogin from 'react-kakao-login';
import styled from 'styled-components';
import { withRouter } from "react-router-dom";
class Login extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
name: '',
provider: '',
 }
 }
// Google Login
responseGoogle = (res) => {
this.setState({
id: res.googleId,
name: res.profileObj.name,
provider: 'google'
 });
this.doSignUp();
 }
// Kakao Login
responseKakao = (res) => {
this.setState({
id: res.profile.id,
name: res.profile.properties.nickname,
provider: 'kakao'
 });
this.doSignUp();
 }
// Login Fail
responseFail = (err) => {
console.error(err);
 }
doSignUp = () => {
const { id, name, provider } = this.state;
window.sessionStorage.setItem('id', id);
window.sessionStorage.setItem('name', name);
window.sessionStorage.setItem('provider', provider);
this.props.onLogin();
this.props.history.push('/');
 }
render() {
return (
<Container>
<GoogleLogin
clientId={process.env.REACT_APP_Google}
buttonText="Google"
onSuccess={this.responseGoogle}
onFailure={this.responseFail}
/>
<KakaoButton
jsKey={process.env.REACT_APP_Kakao}
buttonText="Kakao"
onSuccess={this.responseKakao}
onFailure={this.responseFail}
getProfile="true"
/>
</Container>
 );
 }
}
const Container = styled.div`
 display: flex;
 flex-flow: column wrap;
`
const KakaoButton = styled(KakaoLogin)`
 padding: 0;
 width: 190px;
 height: 44px;
 line-height: 44px;
 color: #783c00;
 background-color: #FFEB00;
 border: 1px solid transparent;
 border-radius: 3px;
 font-size: 16px;
 font-weight: bold;
 text-align: center;
`
export default withRouter(Login);

2) src/App.js

- componentDidMount함수에서 세션스토리지에 id가 있는 경우 onLogin함수를 실행하고 없을 경우에는 onLogout함수를 실행하여 로그인을 유지함.

- 또한 로그아웃 시, 소셜로그인으로 부터 전달받은 토큰을 제거하고 세션스토리지에 저장된 정보를 모두 삭제한다.

import React, { Component } from 'react';
import styled from 'styled-components';
import Header from './Layout/Header';
import Navigation from './Layout/Navigation';
import Router from './Routes/Router';
import Store from './Store/store';
class App extends Component {
constructor(props) {
super(props)
this.state = {
logged: false,
onLogin: this.onLogin,
onLogout: this.onLogout
 }
 }
// Login Func
onLogin = () => {
this.setState({
logged: true
 });
 }
// Logout Func
onLogout = () => {
this.setState({
logged: false
 });
const provider = window.sessionStorage.getItem('provider');
//Google AccessToken Remove
if(provider === 'google') {
const auth2 = window.gapi.auth2.getAuthInstance();
auth2.signOut().then(function() {
console.log('Goolge Logout.');
 });
 }
// Kakao AccessToken Remove
else if(provider === 'kakao'){
window.Kakao.Auth.logout(function() {
console.log("Kakao logout");
 });
 }
//SessionStorage Clear
window.sessionStorage.clear();
 }
componentDidMount() {
const id = window.sessionStorage.getItem('id');
if(id) {
this.onLogin();
 }
else {
this.onLogout();
 }
 }
render() {
const { logged, onLogout } = this.state;
return (
<Store.Provider value={this.state}>
<Layout>
<Header logged={logged} onLogout={onLogout}/>
<Navigation />
<Content>
<Router />
</Content>
</Layout>
</Store.Provider>
 );
 }
}
const Layout = styled.div`
 margin: 0 auto;
 display: flex;
 width: 100%;
 flex-flow: row wrap;
`
const Content = styled.div`
 margin: 0 auto;
`
export default App;

Last updated