Notice
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 취미
- 해외여행
- 스컬킹
- mysql
- 옥길그릭요거트
- 가장존경하는인물
- 일
- 옥길파티룸
- 광명파티룸
- 파티룸
- MBTI
- 보드게임점수계산
- 서울파티룸
- 부천공간대여
- 옥길동파티룸
- 옥길동요거트
- 착한코딩
- 스페이스우일
- 보드게임점수
- 그릭요거트
- 휴식
- 코딩
- 웹개발
- 옥길요거트
- 스컬킹점수계산
- 존경하는위인
- 부천파티룸
- 구로파티룸
- 개발자
- 스컬킹점수
Archives
- Today
- Total
SIMPLE & UNIQUE
5회차_2강 : 로그인을 구현한다. 쿠키로 사용자 세션을 관리한다. 본문
탈잉 강의 자료/react.js(프론트) + node.js(백앤드) 개발에서 배포까지
5회차_2강 : 로그인을 구현한다. 쿠키로 사용자 세션을 관리한다.
착한코딩 2020. 2. 14. 02:105_2 목표 : 홈 화면에서 로그인을 구현한다. 이때 bcrypt 패키지를 사용해 비밀번호를 암호화 한다. 로그인 후 세션 관리 기능을 구현한다.
1. 로그인을 구현해, 그 결과에 따라 유효성을 체크하고 동작을 다르게 처리한다.
1) react 경로 C:\Users\ljung\OneDrive\문서\taling0102\client\src\components에 있는 LoginForm.js를 아래와 같이 수정한다.
import React, { Component } from 'react';
import {Redirect, Link} from 'react-router-dom'
import cookie from 'react-cookies';
import $ from 'jquery';
import axios from "axios";
import Swal from 'sweetalert2'
class LoginForm extends Component {
constructor (props) {
super(props);
this.state = {
prop:props
}
}
submitClick = async e => {
this.email_val = $('#email_val').val();
this.pwd_val = $('#pwd_val').val();
if(this.email_val === '' || this.pwd_val === ''){
this.sweetalert('이메일과 비밀번호를 확인해주세요.', '', 'info', '닫기')
}else{
axios.post('/api/LoginForm?type=signin', {
is_Email: this.email_val,
is_Password: this.pwd_val
})
.then( response => {
try {
var userid = response.data.json[0].useremail
var username = response.data.json[0].username
var userflag = response.data.json[0].userflag
var upw = response.data.json[0].userpassword
if(userid != null && userid != ''){
this.sweetalert('로그인 되었습니다.', '', 'info', '닫기')
//로그인 id 세션에 저장
const expires = new Date()
expires.setMinutes(expires.getMinutes() + 60)
//userid 와 username을 비밀키로 암호화해 쿠키값에 세팅한다.
axios.post('/api/LoginForm?type=SessionState', {
is_Email: userid,
is_UserName: username,
})
.then( response => {
cookie.save('userid', response.data.token1
, {
path: '/',
expires,
// httpOnly: true // 도메인 연결 후 주석해제
})
cookie.save('username', response.data.token2
, {
path: '/',
expires,
// httpOnly: true // 도메인 연결 후 주석해제
})
cookie.save('userpassword', upw
, {
path: '/',
expires,
// httpOnly: true // 도메인 연결 후 주석해제
})
cookie.save('user_flag', 'Y'
, {
path: '/',
expires
}
);
})
.catch( error => {this.sweetalert('작업중 오류가 발생하였습니다.', error, 'error', '닫기'); return false; } );
setTimeout(function() {
window.location.href = '/';
}.bind(this),1000
);
}else{
this.sweetalert('이메일과 비밀번호를 확인해주세요.', '', 'info', '닫기')
}
} catch (error) {
this.sweetalert('이메일과 비밀번호를 확인해주세요.', '', 'info', '닫기')
}
})
.catch( response => { alert(response);return false; } );
}
}
// input value state
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
// login form post
handleSubmit = (e) => {
// submit 페이지 리로딩 방지
e.preventDefault();
}
// 비밀번호 재설정
pwdResetClick = () => {
$('.m_login').hide();
$('.m_pw').fadeIn();
$('.m_pw').css('display','table-cell');
}
//비밀전호 재설정용 메일 발송
sendEmail = (email, subject, text, e) => {
axios.post('/api/message?type=email&roll=resetpw', {
is_Email : email,
is_Subject : subject,
is_Text: text
})
.then( response => {
this.sweetalert('입력하신 이메일로 비밀번호 \n 재설정 메일 보내드렸습니다.', '', 'info', '닫기')
})
.catch( error => {this.sweetalert('작업중 오류가 발생하였습니다.', error, 'error', '닫기');return false;});
}
// //비밀번호 재설정 확인버튼
pwdResetConfim = (e) => {
this.reset_email = $('#reset_email_val').val();
this.reset_name = $('#reset_name_val').val();
if(this.reset_email === '' || this.reset_name === ''){
this.sweetalert('이메일과 성명을 확인해주세요.', '', 'info', '닫기')
}else{
axios.post('/api/LoginForm?type=pwreset', {
is_Email: this.reset_email,
is_Name: this.reset_name,
})
.then( response => {
var userid = response.data.json[0].useremail
var username = response.data.json[0].username
var userpassword = response.data.json[0].userpassword
if(userid != null && userid != ''){
this.sendEmail(userid, 'rtrod 비밀번호 재설정 메일', userpassword)
}else{
this.sweetalert('이메일과 성명을 확인해주세요.', '', 'info', '닫기')
}
})
.catch( response => {this.sweetalert('이메일과 성명을 확인해주세요.', '', 'info', '닫기');return false; } );
}
}
//alert 기본 함수
sweetalert = (title, contents, icon, confirmButtonText) => {
Swal.fire({
title: title,
text: contents,
icon: icon,
confirmButtonText: confirmButtonText
})
}
render () {
return (
<section className="main">
{/* <!-- 로그인폼 --> */}
<div className="m_login">
<h3><span><img src={require("../img/main/log_img.png")} alt="" /></span>LOGIN</h3>
<div className="log_box">
<form onSubmit={this.handleSubmit}>
<div className="in_ty1">
<span><img src={require("../img/main/m_log_i3.png")} alt="" /></span>
<input type="text" id="email_val" name="email" placeholder="이메일" onChange={this.handleChange} />
</div>
<div className="in_ty1">
<span className="ic_2"><img src={require("../img/main/m_log_i2.png")} alt="" /></span>
<input type="password" id="pwd_val" name="password" placeholder="비밀번호" onChange={this.handleChange} />
</div>
<ul className="af">
<li><Link to={'/register_check'}>회원가입</Link></li>
<li className="pwr_b" onClick={this.pwdResetClick}><a href="#n">비밀번호 재설정</a></li>
</ul>
{/* <input className="s_bt" type="submit" value="로그인" /> */}
<button className="s_bt" type="submit" onClick={this.submitClick}>로그인</button>
</form>
</div>
</div>
{/* <!-- 비밀번호 재설정 --> */}
<div className="m_login m_pw">
<h3 className="pw_ls">비밀번호 재설정 <span className="compl1">완료</span></h3>
<div className="log_box">
{/* <!-- 1단 --> */}
{/* <form method="post"> */}
<div className="pw_one">
<div className="in_ty1">
<span><img src={require("../img/main/m_log_i3.png")} alt="" /></span>
<input type="text" id="reset_email_val" name="" placeholder="이메일"/>
</div>
<div className="in_ty1">
<span className=""><img src={require("../img/main/m_log_i1.png")} alt="" /></span>
<input type="text" id="reset_name_val" name="" placeholder="성명"/>
</div>
<div className="btn_confirm btn_confirm_m">
<div className="bt_ty bt_ty_m bt_ty1 cancel_ty1" onClick={this.pwdResetCancleClick}>취소</div>
<a href="#n" className="bt_ty bt_ty_m bt_ty2 submit_ty1" onClick={this.pwdResetConfim}>확인</a>
</div>
</div>
{/* <!-- 2단 가려둠--> */}
<div className="pw_two">
<div className="in_ty1">
<span className="ic_2"><img src={require("../img/main/m_log_i2.png")} alt="" /></span>
<input type="password" name="" placeholder="새 비밀번호" />
</div>
<div className="in_ty1">
<span className="ic_2"><img src={require("../img/main/m_log_i2.png")} alt="" /></span>
<input type="password" name="" placeholder="새 비밀번호 확인" />
</div>
<div className="btn_confirm btn_confirm_m">
<div className="bt_ty bt_ty_m bt_ty1 cancel_ty1">취소</div>
<a href="#n" className="bt_ty bt_ty_m bt_ty2 submit_ty1">재설정</a>
</div>
</div>
{/* <!-- 3단 가려둠 --> */}
<div className="pw_tree">
<div className="">
<p>
'<span>홍길동</span>'
님의 비밀번호가 재설정되었습니다.
</p>
</div>
<input className="s_bt" type="submit" value="로그인 이동" />
</div>
{/* </form> */}
</div>
</div>
</section>
);
}
}
LoginForm.defaultProps = {
}
export default LoginForm;
2) react 경로 C:\Users\ljung\OneDrive\문서\taling0102\client\src\components에 있는 App.js를 아래와 같이 수정
import React, { Component } from 'react';
import { Router, Route, Switch } from "react-router";
import {Redirect} from 'react-router-dom'
import Api_test from './Api_test'
import cookie from 'react-cookies';
import axios from "axios";
// css
import '../css/new.css';
import '../css/owl.carousel.min.css';
import '../css/owl.theme.default.min.css';
// header
import HeaderAdmin from './Header/Header admin';
// footer
import Footer from './Footer/Footer';
// login
import LoginForm from './LoginForm';
// admin floatingPopulationList
import floatingPopulationList from './Floating_population/floatingPopulationList';
// admin softwareinfo
import AdminSoftwareList from './SoftwareToolsManage/AdminSoftwareList';
import AdminSoftwareView from './SoftwareToolsManage/AdminSoftwareView';
// register
import Register from './Register/Register';
import RegisterCheck from './Register/RegisterCheck';
class App extends Component {
constructor (props) {
super(props);
this.state = {
}
}
componentDidMount() {
// 비밀번호 재설정 패이지를 제외하고, 세션이 유효하지 않으면 home url로 이동.
if(window.location.pathname.indexOf('/PwChangeForm') == -1){
//쿠키에서 userid, username을 가져와 복호화한다.
axios.post('/api/LoginForm?type=SessionConfirm', {
token1 : cookie.load('userid')
, token2 : cookie.load('username')
})
.then( response => {
this.state.userid = response.data.token1
let password = cookie.load('userpassword')
if(password == undefined){
password = ''
}
axios.post('/api/LoginForm?type=pwemail', {
is_Email: this.state.userid,
is_Token : password
})
.then( response => {
if(response.data.json[0] !== undefined){
var userid = response.data.json[0].useremail
if(userid == undefined || password == undefined){
window.location.href = '/admin';
}
}else{
// 계정정보가 유효하지 않다면 세션값 삭제후, 홈으로 이동
if(window.location.hash != 'nocookie'){
this.remove_cookie();
window.location.href = '/nocookie/#nocookie';
}
}
})
.catch( response => {
this.remove_cookie()
window.location.href = '/nocookie/#nocookie';
} );
})
.catch( response => {window.location.href = '/nocookie/#nocookie';} );
}
}
//쿠키 초기화
remove_cookie = (e) => {
cookie.remove('userid', { path: '/'});
cookie.remove('username', { path: '/'});
cookie.remove('user_flag', { path: '/'});
cookie.remove('userpassword', { path: '/'});
}
render () {
return (
<div className="App">
<HeaderAdmin/>
<Switch>
{
(cookie.load('userid') !== undefined) ? (
<Route exact path='/' component={AdminSoftwareList} />
):(
<Route exact path='/admin' component={LoginForm} />
)
}
<Route exact path='/' component={LoginForm} />
<Route path='/nocookie' component={LoginForm} />
<Route path='/Api_test' component={Api_test} />
<Route path='/floatPopulationList' component={floatingPopulationList} />
<Route path='/AdminSoftwareList' component={AdminSoftwareList} />
<Route path='/AdminSoftwareView/:swtcode' component={AdminSoftwareView} />
<Route path='/register' component={Register} />
<Route path='/register_check' component={RegisterCheck} />
</Switch>
<Footer
footer_address={this.props.footer_address}
footer_tel={this.props.footer_tel}
footer_email={this.props.footer_email}
footer_mobile={this.props.footer_mobile}
/>
</div>
);
}
}
App.defaultProps = {
// footer value
footer_address: '[34234] 서울특별시 강남구 삼성동 111-114',
footer_tel: '02-1234-5678',
footer_email: 'ljung5@naver.com',
footer_mobile: '010-3288-3398',
};
export default App
3) 로그아웃 처리를 위해 react 경로 C:\Users\ljung\OneDrive\문서\taling0102\client\src\components\Header
에 있는 Header admin.js를 아래와 같이 수정한다.
import React, {Component} from 'react';
import { Link } from 'react-router-dom';
import cookie from 'react-cookies';
import 'react-app-polyfill/ie11';
import axios from "axios";
import Swal from 'sweetalert2'
import $ from 'jquery';
class Header extends Component {
constructor(props) {
super(props);
this.state = {
responseNotice: '', //subcode response 변수
append_NoticeFld: '', //연구분야 append 변수
notice_cnt: '', //알림 갯수
//관리자 세션 처리
admin_usernm:'', //관리자 이름
admin_userid:'', //관리자 아이디
};
this.temp_ref = () => {
$(this).css('display', 'block');
}
}
componentDidMount() {
var cookie_admin_userid = cookie.load('userid')
var cookie_admin_usernm = cookie.load('username')
//사용자가 페이지 로드를 한 시점부터 다시 세션시간 계산
if(cookie_admin_userid != undefined){
const expires = new Date()
expires.setMinutes(expires.getMinutes() + 60)
cookie.save('userid', cookie_admin_userid
, {
path: '/',
expires
}
);
cookie.save('username', cookie_admin_usernm
, {
path: '/',
expires
}
);
cookie.save('user_flag', 'Y'
, {
path: '/',
expires
}
);
$('.menulist').show()
$('.hd_top').show()
}else{
$('.menulist').hide()
$('.hd_top').hide()
}
this.callSessionInfoApi()
}
// 커뮤니티 탭 드롭다운 이벤트
mouseEnter () {
$('.gn_2').stop().slideDown(300);
};
// 커뮤니티 탭 드롭다운 이벤트
mouseLeave () {
$('.gn_2').stop().slideUp(300);
};
// 내 정보 영역 마우스 hover 이벤트
myInfoHover () {
$(".hd_left > li > .box1").stop().fadeIn(400);
}
// 내 정보 영역 마우스 leave 이벤트
myInfoLeave () {
$(".hd_left > li > .box1").stop().fadeOut(400);
}
// 알림 영역 마우스 hover 이벤트
alarmHover = (e) => {
// this.callNoticeApi('display')
}
// 알림 영역 마우스 hover 이벤트
alarmLeave () {
$(".hd_left > li > .box0").stop().fadeOut(400);
}
//로그아웃 아이디 세션 정보 삭제
logout = async e => {
cookie.remove('userid', { path: '/'});
cookie.remove('username', { path: '/'});
cookie.remove('user_flag', { path: '/'});
cookie.remove('userpassword', { path: '/'});
window.location.href = '/admin';
}
// 쿠키값 userid, username 호출
callSessionInfoApi = (type) => {
axios.post('/api/LoginForm?type=SessionConfirm', {
token1 : cookie.load('userid')
, token2 : cookie.load('username')
})
.then( response => {
this.state.admin_usernm = response.data.token2
this.state.admin_userid = response.data.token1
})
.catch( error => {this.sweetalert('작업중 오류가 발생하였습니다.', error, 'error', '닫기');return false;} );
}
//alert 기본 함수
sweetalert = (title, contents, icon, confirmButtonText) => {
Swal.fire({
title: title,
text: contents,
icon: icon,
confirmButtonText: confirmButtonText
})
}
render () {
return(
<header className="gnb_box">
<div className="hd_top">
<div className="top_wrap ct1 af">
<ul className="hd_left af">
<li className="my1" onMouseEnter={this.myInfoHover} onMouseLeave={this.myInfoLeave}><b>내정보</b>
<div className="box0 box1">
<ul>
<li><Link to={'/register'}>내 정보 수정</Link></li>
<li><a href="javascript:" onClick={this.logout}>로그아웃</a></li>
</ul>
</div>
</li>
<li className="my2" onMouseEnter={this.alarmHover} onMouseLeave={this.alarmLeave}><b><span>{this.state.notice_cnt}</span>알림</b>
<div className="box0 box2">
<ul className="al_box">
{this.state.append_NoticeFld}
</ul>
<span className="bt_ty1">
{/* <a href="javascript:" onClick={this.deleteNotice}>알림 모두 제거</a> */}
</span>
</div>
</li>
</ul>
<div className="hd_right">
<p><span>'{this.state.admin_usernm}'</span>님 반갑습니다.</p>
</div>
</div>
</div>
<div className="h_nav ct1 af">
<div className="logo">
<Link to={'/admin'}><img src={require("../../img/layout/logo.jpg")} height="65px" width="200px" alt=""/></Link>
</div>
<nav className="gnb gnb_admin">
<ul className="af">
<li className="menulist">
<Link to={'/UserApproval'}>사용자 관리</Link>
</li>
<li className="menulist">
<Link to={'/AdminResearchProject'}>Research Projects 관리</Link>
</li>
<li className="menulist">
<Link to={'/AdminSoftwareList'}>Software Tools 관리</Link>
</li>
<li className="menulist">
<Link to={'/AdminDataSourceList'}>Data Sources 관리</Link>
</li>
{/* 드롭다운 이벤트 */}
<li className="menulist" onMouseEnter={this.mouseEnter} onMouseLeave={this.mouseLeave} ><Link to={'/floatPopulationList'}>유동인구 조회</Link>
<ul className="gn_2">
<li><Link to={'/community/notice'}>공지사항</Link></li>
</ul>
</li>
<li className="menulist">
<Link to={'/SubCodeManage'}>Sub code 관리</Link>
</li>
</ul>
</nav>
</div>
</header>
);
}
}
export default Header;
## 참고 ##
이 상태에서 로그인이 정상적으로 되면 softwaretool 리스트 페이지로 이동하고, 로그아웃을 하면 다시 로그인 페이지로 이동한다. 로그아웃 상태에서는 페이지 진입을 막기위해 헤더를 hide() 처리했다.
4) 로그인시 bcript사용을 위해 C:\Users\ljung\OneDrive\문서\taling0102\modules\dbconnect_Module.js에 require("bcrypt")부분을 추가한다.
var express = require("express");
var router = express.Router();
const mysql = require("mysql");
const bodyParser = require("body-parser");
const bcrypt = require("bcrypt");
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));
// Connection Pool 세팅
const pool = mysql.createPool({
connectionLimit: 66,
waitForConnections: true,
host: "databaszonaws.com",
....생략....
다음과같이 EC2 서버에 bcript설치 오류가 날 때는, npm install bcry
node-pre-gyp WARN Using request for node-pre-gyp https download
node-pre-gyp ERR! install error
node-pre-gyp ERR! stack Error: The N-API version of this Node instance is 1. This module supports N-API version(s) 3. This Node instance cannot run this module.
node-pre-gyp ERR! stack at Object.module.exports.validate_package_json (/home/ubuntu/20200524/node_modules/node-pre-gyp/lib/util/napi.js:82:9)
node-pre-gyp ERR! stack at validate_config (/home/ubuntu/20200524/node_modules/node-pre-gyp/lib/util/versioning.js:229:10)
node-pre-gyp ERR! stack at Object.module.exports.evaluate (/home/ubuntu/20200524/node_modules/node-pre-gyp/lib/util/versioning.js:279:5)
node-pre-gyp ERR! stack at install (/home/ubuntu/20200524/node_modules/node-pre-gyp/lib/install.js:241:31)
node-pre-gyp ERR! stack at Object.self.commands.(anonymous function) [as install] (/home/ubuntu/20200524/node_modules/node-pre-gyp/lib/node-pre-gyp.js:52:37)
node-pre-gyp ERR! stack at run (/home/ubuntu/20200524/node_modules/node-pre-gyp/bin/node-pre-gyp:82:30)
node-pre-gyp ERR! stack at Object.<anonymous> (/home/ubuntu/20200524/node_modules/node-pre-gyp/bin/node-pre-gyp:134:1)
node-pre-gyp ERR! stack at Module._compile (module.js:652:30)
node-pre-gyp ERR! stack at Object.Module._extensions..js (module.js:663:10)
node-pre-gyp ERR! stack at Module.load (module.js:565:32)
node-pre-gyp ERR! System Linux 4.15.0-1058-aws
node-pre-gyp ERR! command "/usr/bin/node" "/home/ubuntu/20200524/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build"
node-pre-gyp ERR! cwd /home/ubuntu/20200524/node_modules/bcrypt
node-pre-gyp ERR! node -v v8.10.0
node-pre-gyp ERR! node-pre-gyp -v v0.14.0
node-pre-gyp ERR! not ok
The N-API version of this Node instance is 1. This module supports N-API version(s) 3. This Node instance cannot run this module.
npm WARN notsup Unsupported engine for bcrypt@4.0.1: wanted: {"node":">= 10.0.0"} (current: {"node":"8.10.0","npm":"6.14.5"})
npm WARN notsup Not compatible with your version of node/npm: bcrypt@4.0.1
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
'탈잉 강의 자료 > react.js(프론트) + node.js(백앤드) 개발에서 배포까지' 카테고리의 다른 글
5회차_3강 : 이메일 인증을 통한 비밀번호 재설정 기능을 구현한다. (0) | 2020.02.14 |
---|---|
5회차_1강 : 단방향 암호화를 이용해, 회원가입을 구현한다. (0) | 2020.02.13 |
2회차_3강 : 생성한 스키마에 한국시간, 한국 인코딩 설정을 하고 더미데이터를 삽입한다. (0) | 2020.02.09 |
4회차_3강 : NODE 스케줄러를 개발해, EC2 서버에 배포한다. (0) | 2020.01.28 |
4회차_2강 : EC2 서버에 소스파일을 전송 후, 클라우드 서버를 구동한다. (0) | 2020.01.27 |
Comments