-
[Node.js] postman을 이용하여 회원가입 기능 구현하기웹/Node.js & React.js 2022. 2. 12. 01:00
- 명령 프롬프트 창에 node 설치
- node.js의 프레임워크인 express 설치
- mongoDB, mongoose 설치
- ssh 키 생성하여 github에 ssh키 설정
- 서버올리기 : npm start run ( run은 package.json에서 내가 임의로 설정해줌)
- nodemon(서버 변경상태 실시간 감지) : npm start backend ( backend는 package.json에서 내가 임의로 설정해줌)
<기본 세팅>
package.json
- 설치된 패키지들을 관리
- start시, index.js가 먼저 실행되게 함
{ "name": "boiler-plate", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "///", "license": "ISC", "dependencies": { "express": "^4.17.2", "mongoose": "^6.2.1" } }
index.js - mongoDB 연결 부분
-connect()부분에 해당 코드를 입력하면 db랑 연결됨
-정상적으로 연결되면, 웹 브라우저에 localhost:5000/입력시 'hello world' 출력
-console.log를 통해 콘솔창에도 출력됨
const express = require('express') const app = express() const port = 5000 const mongoose = require('mongoose') mongoose.connect('mongodb+srv://USERNAME:1234@boilerplate.abcmn.mongodb.net/myFirstDatabase?retryWrites=true&w=majority').then(() => console.log('MongoDB connected...')) .catch(err => console.log(err)) app.get('/', (req,res) => res.send('Hello World')) app.listen(port, () => console.log(`Example app listening on port ${port}`))
User.js
- schema : 정보를 나타냄
ex) 회원가입시, 필요한 정보들을 지정함 : name,email,pw ...
- module : 만든 스키마를 모듈화함
const User = mongoose.model('User', userSchema)module.exports = {User}const mongoose = require('mongoose') const userSchema = mongoose.Schema({ name: { type:String, maxlength:50 }, email: { type: String, trim: true, unique:1 }, password: { type:String, minlength:5 }, lastname:{ type:String, maxlength:50 }, role: { type:Number, default: 0 }, image :String, token: { type:String }, tokenExp: { type: Number } }) const User = mongoose.model('User', userSchema) module.exports = {User}
<postman 이용>
- postman?
API 개발을 보다 빠르고 쉽게 구현 할 수 있도록 도와주며,
개발된 API를 테스트하여 문서화 또는 공유 할 수 있도록 도와 주는 플랫폼
쉽게말해서, url로 테스트하는데는 한계가 있으니까 편리하게 테스트하는데 필요한 인터페이스임!
https://www.postman.com/downloads/
- body-parser dependency 설치
클라이언트(브라우저)가 보낸 자료들을 body-parser를 이용해서 서버에서 받음!
index.js
const express = require('express') const app = express() const port = 5000 const bodyParser =require('body-parser') const { User } = require('./model/User') /*body-parser 옵션*/ //application/x-www-form-urlencoded 처럼 생긴 데이터를 분석해서 가져올수 있게함 app.use(bodyParser.urlencoded({extended:true})) //application/json 타입을 가져옴 app.use(bodyParser.json()) const mongoose = require('mongoose') mongoose.connect('mongodb+srv://username:1234@boilerplate.abcmn.mongodb.net/myFirstDatabase?retryWrites=true&w=majority').then(() => console.log('MongoDB connected...')) .catch(err => console.log(err)) //url 이용 app.get('/', (req,res) => res.send('Hello World')) //postman 이용: register route - 회원가입을 위한 register route app.post('/register', (req, res) => { //회원가입할때 필요한 정보들을 client에서 가져오면 //그것들을 데이터 베이스에 넣어준다. const user = new User(req.body) user.save((err,userInfo) => { if(err) return res.json({ success:false, err}) return res.status(200).json({ success: true }) }) //정보들이 user모델에 저장 }) app.listen(port, () => console.log(`Example app listening on port ${port}`))
- db에 잘 넣어지면 json형식으로 true, 실패시 false가 postman에 출력됨
- postman에 임의로 회원가입 양식을 json형식으로 입력함
- /register : 앤드포인트
<보안 설정>
1. 비밀 설정 정보 관리
- dev.js , prod.js로 나누기
- 보통 서버개발 환경은 local - dev - staging - product 로 나뉨
local : 내 pc
dev : 개발자들이 local에서 만든 코드를 합쳐서 테스트 해보는 서버
staging : 실제 운영 환경과 동일하게 만들어 테스트
prod : 실제 서비스 운영 서버
- 조건문을 통해 내 mongodb 정보를 가리기
dev.js (개인정보)
- .gitignore에 dev.js를 추가하여 github에 올릴때 dev.js 파일은 올리지 못하게 함
module.exports = { mongoURI:'mongodb+srv://username:dddd@boilerplate.abcmn.mongodb.net/myFirstDatabase?retryWrites=true&w=majority' }
prod.js
module.exports = { mongoURI: process.env.MONGO_URI }
key.js
- production(배포) 상태하면 prod.js 실행할 것 (임의로 설정한 것임)
if(process.env.NODE_ENV === 'production') { module.exports = require('./prod') }else { module.exports = require('./dev') }
index.js (추가)
const config = require('./config/key') const mongoose = require('mongoose') mongoose.connect(config.mongoURI).then(() => console.log('MongoDB connected...')) .catch(err => console.log(err))
2. bcrypt로 비밀번호 암호화
- 비밀번호를 암호화하여 db에 저장하자
해싱 vs 암호화
: 암호화는 복호화 가능한 양방향의 방향성, 해싱은 복호화가 불가능한 단방향의 방향성
: 따라서 비밀번호는 해싱을 이용해야 함
- 해싱에다가 salt 기법을 추가하여 보안을 더 견고하게 만들 수 있음
즉, 해싱값에 무작위 문자열을 더 추가한다(해싱에 소금치기...ㅎㅎ)
- bcrypt 를 이용하자
User.js(추가)
- index.js의 save()함수 (db에 저장하는 메서드) 를 수행하기 전에 먼저 수행하는 함수
- pre() : 성공적으로 실행되면 next()즉, save() 함수가 실행된다.
- 비밀번호가 바뀌었을 때만 암호화 함(isModified)
const bcrypt = require('bcrypt') const saltRounds =10 //임의 추가할 문자열의 개수 //save()호출전에 시행 mongoose에서 가져온 메소드 userSchema.pre('save', function( next ){ var user = this; if(user.isModified('password')){ //비밀번호를 암호화 시킨다. bcrypt.genSalt(saltRounds, function(err,salt){ if(err) return next(err) bcrypt.hash(user.password, salt, function(err,hash){ if(err) return next(err) user.password = hash next() }); }); } else { next() } }); const User = mongoose.model('User', userSchema) module.exports = {User}
index.js
app.post('/register', (req, res) => { //회원가입할때 필요한 정보들을 client에서 가져오면 //그것들을 데이터 베이스에 넣어준다. const user = new User(req.body) user.save((err,userInfo) => { if(err) return res.json({ success:false, err}) return res.status(200).json({ success: true }) }) //정보들이 user모델에 저장 })
- db에 암호화 되어 저장된 모습
<로그인>
- 로그인후 토큰 생성
User.js
- 원래 상태의 비밀번호(암호화 전)와 암호화된 비밀번호를 비교하는 함수
- 토큰 생성
userSchema.methods.generateToken = function(cb) { var user = this //jsonwebtoken을 이용해서 토큰을 생성하기 var token = jwt.sign(user._id.toHexString(),'secretToken') user.token = token user.save(function(err,user) { if(err) return cb(err) cb(null, user) }) } userSchema.methods.comparePassword = function(plainPassword, callbackfunction) { //plainpw 와 암호화된 비밀번호가 맞는 지 확인. plainpw를 암호화 해서 비교한다. bcrypt.compare(plainPassword, this.password, function(err, isMatch){ if(err) return callbackfunction(err), callbackfunction(null, isMatch) }) }
index.js
- 로그인 성공시 토큰 생성
app.post('/login', (req, res) => { //요청된 이메일을 데이터베이스에서 있는지 찾는다 User.findOne({ email: req.body.email }, (err, user) => { if(!user){ return res.json({ loginSucess: false, message :"제공된 이메일에 해당하는 유저가 없습니다." }) } //요청된 이메일이 데이터베이스에 있다면 비밀번호가 맞는 비밀번호 인지 확인 user.comparePassword(req.body.password , (err, isMatch) => { if(!isMatch) return res.json({loginSucess: false ,message: "비밀번호가 틀렸습니다."}) //비밀번호까지 맞다면 토큰을 생성하기 user.generateToken((err, user) => { if(err) return res.status(400).send(err); // 토큰을 저장한다. 어디에? 쿠키, 로컬스토리지 res.cookie("x_auth",user.token) .status(200) .json({ loginSucess:true, userId: user._id}) }) }) }) })
<Auth 생성>
- auth 란? 특정 권한을 가진 유저만 해당하는 페이지를 볼 수 있도록 제한하는 기능
ex) 관리자 신분을 가진 user만 관리자 페이지 볼 수 있음, 로그인한 유저만 해당 페이지 볼 수 있음
- client의 쿠키에 담겨져 있는 토큰을 복호화 한 후 server의 db에 담겨져 있는 토큰과 비교하여
일치하면 auth 인증이 완료됨
auth.js
const {User} = require('../model/User') let auth =(req, res, next) => { //인증 처리를 하는 곳 //클라이언트 쿠키에서 토큰을 가져온다. let token = req.cookies.x_auth; // 클라이언트의 토큰을 복호화 한 후 유저를 찾는다 User.findByToken(token, (err,user) => { if(err) throw err; if(!user) return res.json({ isAuth :false,error : true}) req.token =token req.user = user; next(); // next가 없으면 미들웨어에 갇힘 }) // 유저가 있으면 인증 ok // 유저가 없으면 인증 no } module.exports = {auth}
User.js
- 토큰을 복호화 하는 method
userSchema.statics.findByToken = function(token, cb){ var user = this; //user._is +' ' =token //토큰을 decode한다. jwt.verify(token,'secretToken', function(err, decoded) { //유저 아이디를 이용해서 유저를 찾은 다음에 //클라이언트에서 가져온 token과 db에 보관된 토큰이 일치하는지 확인 user.findOne({"_id": decoded, "token": token}, function(err,user){ if(err) return cb(err); cb(null, user) }) }) }
index.js
app.get('/api/users/auth', auth, (req,res) => { // 여기 까지 미들웨어를 통과해 왔다는 얘기는 authentication이 true 라는 말 res.status(200).json({ _id: req.user._id, isAdmin: req.user.role === 0 ? false: true, isAuth: true, email: req.user.email, name:req.user.name, lastname: req.user.lastname, role :req.user.role, image: req.user.image }) })
<로그아웃>
- 로그아웃 하려는 유저를 찾아서 server의 db에서 해당 유저의 토큰을 삭제함
index.js
- mongoose의 함수를 이용함(findoneandupdate)
- token을 삭제함
app.get('/api/users/logout', auth, (req,res) => { User.findOneAndUpdate({ _id: req.user._id} , {token:""}, (err,user) =>{ if(err) return res.json({success:false, err}); return res.status(200).send({ success: true }) }) })
'웹 > Node.js & React.js' 카테고리의 다른 글
[React] 안드로이드로 react-native 연결하고 카메라 띄우기 (0) 2022.04.26 [React] React-Native로 안드로이드 에뮬레이터 실행하기 (0) 2022.04.25 [Node&React] 오류 (0) 2022.03.16 [React.js] 리액트를 이용해서 회원가입 페이지 만들기 (0) 2022.02.13