일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 파티룸
- 코딩
- 취미
- 부천공간대여
- 스페이스우일
- 구로파티룸
- 옥길그릭요거트
- 휴식
- 옥길동그릭요거트
- 개발자
- 보드게임점수
- 서울파티룸
- MBTI
- 옥길동파티룸
- 스컬킹점수계산
- 옥길동요거트
- 옥길요거트
- 스컬킹
- 옥길파티룸
- 착한코딩
- 광명파티룸
- 스컬킹점수
- 웹개발
- 보드게임점수계산
- 해외여행
- 그릭요거트
- 부천시그릭요거트
- 부천요거트맛집
- 일
- 부천파티룸
- Today
- Total
SIMPLE & UNIQUE
4-2강 : 로그인 기능 구현, 쿠키로 로그인 세션 관리 본문
4_2 목표 : 회원가입에 사용한 bcrypt패키지를 사용해, 로그인 비밀번호를 회원정보에 저장된 비밀번
호와 비교한다. 로그인이 완료되면 쿠키에 회원정보를 저장하고, 관리한다.
1. 로그인을 구현해, 그 결과에 따라 유효성을 체크하고 동작을 다르게 처리한다.
1) react 경로 C:\react200\client 에 쿠키 패키지 react-cookies를 설치한다.
npm install react-cookies --save
2) react 경로 C:\react200\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:\react200\client\src\components에 있는 App.js를 아래와 같이 수정
import React, { Component } from 'react';
import { Route } from "react-router-dom";
import cookie from 'react-cookies';
import axios from "axios";
// css
import '../css/new.css';
// header
import HeaderAdmin from './Header/Header admin';
// footer
import Footer from './Footer/Footer';
// login
import LoginForm from './LoginForm';
import SoftwareList from './SoftwareToolsManage/SoftwareList';
import SoftwareView from './SoftwareToolsManage/SoftwareView';
import Register from './Register/Register';
class App extends Component {
constructor(props) {
super(props);
this.state = {
}
}
componentDidMount() {
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){
axios.post('/api/LoginForm?type=SessionSignin', {
is_Email: this.state.userid,
is_Token : password
})
.then( response => {
if(response.data.json[0].useremail === undefined){
this.noPermission()
}
})
.catch( error => {
this.noPermission()
});
}else{
this.noPermission()
}
})
.catch( response => this.noPermission());
}
noPermission = (e) => {
if(window.location.hash != 'nocookie'){
this.remove_cookie();
window.location.href = '/login/#nocookie';
}
};
remove_cookie = (e) => {
cookie.remove('userid', { path: '/'});
cookie.remove('username', { path: '/'});
cookie.remove('userpassword', { path: '/'});
}
render () {
return (
<div className="App">
<HeaderAdmin/>
<Route exact path='/' component={LoginForm} />
<Route path='/login' component={LoginForm} />
<Route path='/SoftwareList' component={SoftwareList} />
<Route path='/SoftwareView/:swtcode' component={SoftwareView} />
<Route path='/register' component={Register} />
<Footer/>
</div>
);
}
}
export default App;
3) 로그아웃 처리를 위해 react 경로 C:\react200\client\src\components\Header
에 있는 Header admin.js를 아래와 같이 수정한다.
import React, {Component} from 'react';
import { Link } from 'react-router-dom';
import axios from "axios";
import cookie from 'react-cookies';
import $ from 'jquery';
import Swal from 'sweetalert2';
class Header extends Component {
constructor(props) {
super(props);
this.state = {
usernm:'',
};
}
componentDidMount() {
var cookie_userid = cookie.load('userid')
var cookie_usernm = cookie.load('username')
var cookie_password = cookie.load('userpassword')
if(cookie_userid != undefined){
const expires = new Date()
expires.setMinutes(expires.getMinutes() + 60)
cookie.save('userid', cookie_userid
, { path: '/', expires })
cookie.save('username', cookie_usernm
, { path: '/', expires })
cookie.save('userpassword', cookie_password
, { path: '/', expires })
$('.menulist').show()
$('.hd_top').show()
}else{
$('.menulist').hide()
$('.hd_top').hide()
}
this.callSessionInfoApi()
}
callSessionInfoApi = (type) => {
axios.post('/api/LoginForm?type=SessionConfirm', {
token1 : cookie.load('userid')
, token2 : cookie.load('username')
})
.then( response => {
this.setState({usernm : response.data.token2})
})
.catch( error => {
this.sweetalert('작업중 오류가 발생하였습니다.', error, 'error', '닫기');
});
}
sweetalert = (title, contents, icon, confirmButtonText) => {
Swal.fire({
title: title,
text: contents,
icon: icon,
confirmButtonText: confirmButtonText
})
}
myInfoHover () {
$(".hd_left > li > .box1").stop().fadeIn(400);
}
myInfoLeave () {
$(".hd_left > li > .box1").stop().fadeOut(400);
}
logout = async e => {
cookie.remove('userid', { path: '/'});
cookie.remove('username', { path: '/'});
cookie.remove('userpassword', { path: '/'});
window.location.href = '/login';
}
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><a>내 정보 수정</a></li>
<li><a href="javascript:" onClick={this.logout}>로그아웃</a></li>
</ul>
</div>
</li>
<li className="my2"><b><span>0</span>알림</b>
</li>
</ul>
<div className="hd_right">
<p><span>'{this.state.usernm}'</span>님 반갑습니다.</p>
</div>
</div>
</div>
<div className="h_nav ct1 af">
<div className="logo">
<Link to={'/'}><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={'/SoftwareList'}>Software Tools 관리</Link>
</li>
<li className="menulist">
<Link to={'/AdminDataSourceList'}>Data Sources 관리</Link>
</li>
{/* 드롭다운 이벤트 */}
<li className="menulist"><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() 처리했다.
2. node 경로(C:\react200)에 회원가입관련 코드를 추가한다.
1) server.js 파일을 아래와 같이 수정한다.
var express = require('express');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var swtoolRouter = require("./routes/SwtoolRout");
var fileuploadRouter = require("./routes/UploadRout");
var usersRouter = require("./routes/UsersRout");
require("./routes/BatchRout");
var app = express();
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use("/api/Swtool", swtoolRouter);
app.use("/api/upload", fileuploadRouter);
app.use(express.static("./uploads"));
app.use("/api/register", usersRouter);
app.use("/api/LoginForm", usersRouter);
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Listening on port ${port}`));
2) 로그인 세션 관리를 위해 사용할 jsonwebtoken 패키지를 설치한다.
npm install jsonwebtoken --save
3) 노드경로 C:\react200에 ignorefile 폴더를 생성하고, jwt.js 파일을 생성해 아래 코드를 붙여넣는다. 아래 react200 문자열이 비밀키인데, 아무 문자열이든 상관없지만 유출되지 않도록 조심한다. git을 사용할 때도 예외처리 해줘야한다.
let jwtObj = {};
jwtObj.secret = "react200"
module.exports = jwtObj
4) 노드경로 C:\react200\routes에 UsersRout.js 파일에 아래 코드를 붙여넣는다.
var express = require('express');
var router = express.Router();
const bodyParser = require('body-parser');
const bcrypt = require('bcrypt');
const saltRounds = 10;
let jwt = require("jsonwebtoken");
let secretObj = require("../ignorefile/jwt");
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));
router.post('/', (req, res, next) => {
var type = req.query.type;
if(type == "signup"){
//회원가입 정보 삽입
try {
// Mysql Api 모듈(CRUD)
var dbconnect_Module = require('./dbconnect_Module');
//Mysql 쿼리 호출정보 입력
req.body.mapper = 'UserMapper';//mybatis xml 파일명
req.body.crud = 'insert';//select, insert, update, delete 중에 입력
req.body.mapper_id = 'insertUser';
var myPlaintextPassword = req.body.is_Password;
if(myPlaintextPassword != '' && myPlaintextPassword != undefined ){
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPassword, salt, function(err, hash) {
req.body.is_Password = hash;
router.use('/', dbconnect_Module);
next('route')
});
});
}else{
router.use('/', dbconnect_Module);
next('route')
}
} catch (error) {
console.log("Module > dbconnect error : "+ error);
}
}else if(type == "dplicheck"){
//이메일 중복체크
try {
// Mysql Api 모듈(CRUD)
var dbconnect_Module = require('./dbconnect_Module');
//Mysql 쿼리 호출정보 입력
req.body.mapper = 'UserMapper';//mybatis xml 파일명
req.body.crud = 'select';//select, insert, update, delete 중에 입력
req.body.mapper_id = 'selectUserDpliCheck';
router.use('/', dbconnect_Module);
next('route')
} catch (error) {
console.log("Module > dbconnect error : "+ error);
}
}else if(type == "signin"){
//로그인 조회
try {
// Mysql Api 모듈(CRUD)
var dbconnect_Module = require('./dbconnect_Module');
//Mysql 쿼리 호출정보 입력
req.body.mapper = 'UserMapper';//mybatis xml 파일명
req.body.crud = 'select';//select, insert, update, delete 중에 입력
req.body.mapper_id = 'selectLoginCheck';
router.use('/', dbconnect_Module);
next('route')
} catch (error) {
console.log("Module > dbconnect error : "+ error);
}
}else if(type == "SessionState"){
var userid = req.body.is_Email
var name = req.body.is_UserName
try {
let token1 = jwt.sign(
{ email: userid },
secretObj.secret,
{ expiresIn: '60m' })
let token2 = jwt.sign(
{ username: name },
secretObj.secret,
{ expiresIn: '60m' })
res.send({"token1":token1, "token2":token2});
} catch (error) {
res.send(error)
}
}else if(type == "SessionConfirm"){
try {
let token1 = req.body.token1;
let token2 = req.body.token2;
if(token1 != undefined && token1 != '' & token2 != undefined && token2 != ''){
let decoded1 = jwt.verify(token1, secretObj.secret);
let decoded2 = jwt.verify(token2, secretObj.secret);
res.send({"token1":decoded1.email, "token2":decoded2.username});
}else{
res.send({"token1":"", "token2":""});
}
} catch (error) {
res.send(error)
}
}else if(type == "SessionSignin"){
// 쿠키 정보로 사용자 인증
try {
// Mysql Api 모듈(CRUD)
var dbconnect_Module = require('./dbconnect_Module');
//Mysql 쿼리 호출정보 입력
req.body.mapper = 'UserMapper';//mybatis xml 파일명
req.body.crud = 'select';//select, insert, update, delete 중에 입력
req.body.mapper_id = 'selectSessionLoginCheck';
router.use('/', dbconnect_Module);
next('route')
} catch (error) {
console.log("Module > dbconnect error : "+ error);
}
}
});
module.exports = router;
5) 노드경로 C:\react200\models에 UserMapper.xml 파일을 생성하고 아래 코드를 붙여넣는다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="UserMapper">
<insert id="insertUser">
INSERT INTO react.react_user
(
username
, userorg
, useremail
, userpassword
, usermajor
, userphone
, userflag
, reg_date
, reg_user
, update_date
, update_user
)
VALUES (
#{is_Username}
, #{is_Organization}
, CONCAT(#{is_Useremail1}, '@', #{is_Useremail2})
, #{is_Password}
, #{is_Usermajor}
, CONCAT(#{is_Userphone1}, '-', #{is_Userphone2},'-', #{is_Userphone3})
, 'Y'
, DATE_FORMAT(now(), '%Y%m%d%H%i%s')
, CONCAT(#{is_Useremail1}, '@', #{is_Useremail2})
, DATE_FORMAT(now(), '%Y%m%d%H%i%s')
, CONCAT(#{is_Useremail1}, '@', #{is_Useremail2})
)
</insert>
<select id="selectUserDpliCheck">
SELECT
count(*) as num
FROM
react.react_user
WHERE useremail = #{is_Email}
</select>
<select id="selectLoginCheck">
SELECT
username
, userorg
, useremail
, userpassword
, usermajor
, userphone
, userflag
FROM
react.react_user
WHERE useremail = #{is_Email}
</select>
<select id="selectSessionLoginCheck">
SELECT
username
, userorg
, useremail
, userpassword
, usermajor
, userphone
, userflag
FROM
react.react_user
WHERE useremail = #{is_Email}
AND userpassword = #{is_Token}
</select>
</mapper>
6) C:\react\dbconnect_Module.js에 bcrypt패키지 사용부분을 추가한다. mapper id가 selectLoginCheck인 경우, 로그인 비밀번호와 db에 저장된 회원비밀번호를 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: "react200.#######.ap-northeast-2.rds.amazonaws.com",
port: "3306",
database: 'react',
user: "admin",
password: "react200RDS",
});
router.post("/", (req, res) => {
const mybatisMapper = require("mybatis-mapper");
var param = req.body;
//mybatis mapper경로 설정
mybatisMapper.createMapper(['./models/'+param.mapper+'.xml']);
var time = new Date();
console.log('## '+time+ ' ##');
console.log("\n Called Mapper Name = "+param.mapper);
var format = { language: 'sql', indent: ' ' };
//mysql 쿼리 정보 세팅
var query = mybatisMapper.getStatement(param.mapper, param.mapper_id, param, format);
console.log("\n========= Node Mybatis Query Log Start =========");
console.log("* mapper namespce : "+param.mapper+"."+param.mapper_id+" *\n");
console.log(query+"\n");
try {
pool.getConnection(function(err,connection){
connection.query(query, function (error, results) {
if (error) {
console.log("db error************* : "+error);
}
var time2 = new Date();
console.log('## '+time2+ ' ##');
console.log('## RESULT DATA LIST ## : \n', results);
if(results != undefined){
string = JSON.stringify(results);
var json = JSON.parse(string);
if (req.body.crud == "select") {
if (param.mapper_id == "selectLoginCheck") {
if (json[0] == undefined) {
res.send(null);
} else {
bcrypt.compare(req.body.is_Password, json[0].userpassword, function(
err,
login_flag
) {
if (login_flag == true) {
res.send({ json });
} else {
res.send(null);
}
});
}
} else {
res.send({ json });
}
}else{
res.send("succ");
}
}else{
res.send("error");
}
connection.release();
console.log("========= Node Mybatis Query Log End =========\n");
});
})
} catch (error) {
console.log("pool error : "+error);
}
});
module.exports = router;
6) 로그인 완료 후, 크롬 개발자도구 > Application탭 > Storage > Cookies > http://localhost:300 순서로 클릭하면, 다음과 같이 쿠키에 jwt로 인코딩 + 암호화 처리된 회원정보가 세팅된 것을 확인할 수 있다.
https://taling.me/Talent/Detail/19341
강의 문의 : ljung5@naver.com
'탈잉 강의 자료 > 2020_비전공자도 가능한 웹 프로젝트' 카테고리의 다른 글
4-3강 : 이메일 인증을 사용한, 비밀번호 재설정 구현 (0) | 2020.08.03 |
---|---|
4-1강 : 회원 가입 기능 구현, 비밀번호 단반향 암호화 (0) | 2020.08.03 |
3-4강 : 배치(스케줄러) 구현, EC2서버에 배포 (0) | 2020.08.03 |
3-3강 : EC2서버에 NODE 설치, 서버 구동 후 외부 접속 (0) | 2020.08.03 |
3-2강 : AWS 웹 서버 인스턴스 생성, SFTP & SSH 연결 (1) | 2020.08.03 |