Showing
6 changed files
with
152 additions
and
154 deletions
This diff could not be displayed because it is too large.
1 | { | 1 | { |
2 | - "name": "boiler-plate", | 2 | + "name": "react-boiler-plate", |
3 | "version": "1.0.0", | 3 | "version": "1.0.0", |
4 | - "description": "", | 4 | + "description": "react boiler plate", |
5 | "main": "index.js", | 5 | "main": "index.js", |
6 | + "engine": { | ||
7 | + "node": "10.16.0", | ||
8 | + "npm": "6.9.0" | ||
9 | + }, | ||
6 | "scripts": { | 10 | "scripts": { |
7 | "start": "node server/index.js", | 11 | "start": "node server/index.js", |
8 | "backend": "nodemon server/index.js", | 12 | "backend": "nodemon server/index.js", |
9 | - "test": "echo \"Error: no test specified\" && exit 1", | 13 | + "frontend": "npm run start --prefix client", |
10 | - "dev" : "concurrently \"npm run backend\" \"npm run start --prefix client\"" | 14 | + "dev": "concurrently \"npm run backend\" \"npm run start --prefix client\"" |
11 | }, | 15 | }, |
12 | - "author": "mindyeoi", | 16 | + "author": "John ahn", |
13 | "license": "ISC", | 17 | "license": "ISC", |
14 | "dependencies": { | 18 | "dependencies": { |
15 | - "bcrypt": "^5.0.1", | 19 | + "bcrypt": "^3.0.6", |
16 | - "body-parser": "^1.19.0", | 20 | + "body-parser": "^1.18.3", |
17 | - "concurrently": "^6.2.0", | 21 | + "cookie-parser": "^1.4.3", |
18 | - "cookie-parser": "^1.4.5", | 22 | + "cors": "^2.8.5", |
23 | + "debug": "^4.1.1", | ||
19 | "express": "^4.17.1", | 24 | "express": "^4.17.1", |
20 | "jsonwebtoken": "^8.5.1", | 25 | "jsonwebtoken": "^8.5.1", |
21 | - "mongoose": "^5.12.12" | 26 | + "moment": "^2.24.0", |
27 | + "mongoose": "^5.4.20", | ||
28 | + "react-redux": "^5.0.7", | ||
29 | + "saslprep": "^1.0.3", | ||
30 | + "supports-color": "^7.1.0" | ||
22 | }, | 31 | }, |
23 | "devDependencies": { | 32 | "devDependencies": { |
24 | - "nodemon": "^2.0.7" | 33 | + "concurrently": "^4.1.0", |
34 | + "nodemon": "^1.19.1" | ||
25 | } | 35 | } |
26 | } | 36 | } | ... | ... |
1 | -const express = require('express') | 1 | +const express = require("express") |
2 | const app = express() | 2 | const app = express() |
3 | -const port = 5000 | 3 | +const port = process.env.PORT || 5000 |
4 | 4 | ||
5 | -// User.js에서 만든 model을 가져옴 | 5 | +const path = require("path"); |
6 | -const { User } = require('./models/User') | 6 | +const cors = require('cors') |
7 | -//const { User } = require('./') | ||
8 | 7 | ||
9 | // body-parser 가져옴 | 8 | // body-parser 가져옴 |
10 | const bodyParser = require('body-parser') | 9 | const bodyParser = require('body-parser') |
11 | // bodyParser option | 10 | // bodyParser option |
12 | app.use(bodyParser.urlencoded({extended: true})) //application/x-www-form-urlencoded로 된 데이터를 분석해서 가져옴 | 11 | app.use(bodyParser.urlencoded({extended: true})) //application/x-www-form-urlencoded로 된 데이터를 분석해서 가져옴 |
13 | app.use(bodyParser.json()) // application/json 타입으로 된 데이터를 분석해서 가져옴 | 12 | app.use(bodyParser.json()) // application/json 타입으로 된 데이터를 분석해서 가져옴 |
13 | +const cookieParser = require("cookie-parser"); | ||
14 | +app.use(cookieParser()); | ||
15 | +const config = require("./config/key"); | ||
14 | 16 | ||
15 | -const config = require('./config/key') | ||
16 | 17 | ||
17 | -const cookieParser = require('cookie-parser') | 18 | +const mongoose = require("mongoose"); |
18 | -app.use(cookieParser()) | ||
19 | 19 | ||
20 | -const mongoose = require('mongoose') | ||
21 | 20 | ||
22 | -const { auth } = require('./middleware/auth') | 21 | +const connect = mongoose.connect(config.mongoURI, |
23 | - | ||
24 | -//이 정보는 비밀임..! 몽고DB아이디랑 비밀번호를 감춰야해..! | ||
25 | -mongoose.connect(config.mongoURI, { | ||
26 | - useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false | ||
27 | -}).then(()=>console.log('MongoDB Connected...')) | ||
28 | -.catch(err => console.log(err)) | ||
29 | - | ||
30 | -app.get('/', (req, res) => { | ||
31 | - res.send('민정이짱짱맨최고최고!') | ||
32 | -}) | ||
33 | - | ||
34 | -// 회원가입 구현 | ||
35 | -// route의 endpoint는 register | ||
36 | -app.post('/api/users/register', (req, res) => { | ||
37 | - // 회원가입할 때 필요한 정보들을 client에서 가져오면 | ||
38 | - // 그것들을 데이터베이스에 넣어준다. | ||
39 | - | ||
40 | - const user = new User(req.body) // req.body에 User의 정보를 저장 | ||
41 | - | ||
42 | - // 비밀번호 암호화 | ||
43 | - | ||
44 | - | ||
45 | - // mongoDB에서 오는 메서드. 정보들이 user model에 저장 | ||
46 | - user.save((err, userInfo) => { | ||
47 | - // 만약 에러가 나면, json형식으로 success:false를 보내주고, 에러메시지를 보내줌 | ||
48 | - if(err) return res.json({success: false, err}) | ||
49 | - // 성공하면 status(200) (status(200)은 성공했다는 뜻) | ||
50 | - return res.status(200).json({ | ||
51 | - success: true | ||
52 | - }) | ||
53 | - }) | ||
54 | - | ||
55 | -}) | ||
56 | - | ||
57 | -// 로그인 구현 -> 로그인 하면 토큰 생성 | ||
58 | -app.post('/api/users/login', (req, res) => { | ||
59 | - // 1. 요청된 이메일이 데이터베이스에 있는지 찾기 | ||
60 | - User.findOne({ email: req.body.email }, (err, user) => { | ||
61 | - if(!user) | ||
62 | { | 22 | { |
63 | - return res.json({ | 23 | + useNewUrlParser: true, useUnifiedTopology: true, |
64 | - loginSuccess: false, | 24 | + useCreateIndex: true, useFindAndModify: false |
65 | - message: "There is no user with that email." | ||
66 | - }) | ||
67 | - } | ||
68 | - // 2. email과 비밀번호가 맞는지 확인 (User.js에 comparePassword 함수 정의되어 있음) | ||
69 | - user.comparePassword(req.body.password, (err, isMatch) => { | ||
70 | - if(!isMatch) | ||
71 | - return res.json({loginSuccess: false, message: "Password is not match."}) | ||
72 | - // 3. 비밀번호까지 맞다면 유저를 위한 토큰 생성 (User.js에 generateToken 함수 정의) | ||
73 | - user.generateToken((err, user) => { // err가 없으면 user에 정보 받아옴 | ||
74 | - if(err) | ||
75 | - return res.status(400).send(err); | ||
76 | - // 4. 생성한 토큰을 저장함 -> 쿠키나 로컬 스토리지 등에 저장할 수 있는데 여기선 쿠키에 저장 | ||
77 | - res.cookie("loginCookie", user.token) | ||
78 | - .status(200) //성공했다는 표시 | ||
79 | - .json({loginSuccess: true, userId: user._id}) | ||
80 | - }) | ||
81 | - }) | ||
82 | }) | 25 | }) |
83 | -}) | 26 | + .then(() => console.log('MongoDB ---> Connected')) |
27 | + .catch(err => console.log(err)); | ||
84 | 28 | ||
29 | +app.use(cors()) | ||
85 | 30 | ||
86 | -// 인증 구현 (이 사람이 일반유저인지 관리자인지) | ||
87 | -app.get('/api/users/auth', auth ,(req,res) => { | ||
88 | - // 여기까지 미들웨어(auth) 통과했으면 authentication == true 라는 뜻 | ||
89 | - res.status(200).json({ | ||
90 | - _id: req.user._id, | ||
91 | - isAdmin: req.user.role === 0 ? false : true, // role이 0이면 일반 유저, role이 0이 아니면 관리자. | ||
92 | - isAuth: true, | ||
93 | - email: req.user.email, | ||
94 | - lastname: req.user.lastname, | ||
95 | - role: req.user.role, | ||
96 | - image: req.user.image | ||
97 | - }) | ||
98 | -}) | ||
99 | 31 | ||
100 | -// 로그아웃 구현 (로그인 때 만든 토큰을 지워버림) | 32 | +app.use('/api/users', require('./routes/users')); |
101 | -app.get('/api/users/logout', auth, (req, res) => { | 33 | + |
102 | - User.findOneAndUpdate({_id: req.user._id}, // id로 User를 찾아서 업데이터 시킴 | ||
103 | - { token: "" }, (err, user) => { | ||
104 | - if(err) return res.json({success: false, err}); | ||
105 | - return res.status(200).send({ | ||
106 | - success: true | ||
107 | - }) | ||
108 | - }) | ||
109 | -}) | ||
110 | 34 | ||
111 | -// test | 35 | +// 이미지 가져오려고 |
112 | -app.get('/api/hello', (req, res) => { | 36 | +app.use('/uploads', express.static('uploads')); |
113 | 37 | ||
114 | - res.send("hello"); | 38 | +if (process.env.NODE_ENV === "production") { |
115 | -}) | 39 | + app.use(express.static("client/build")); |
40 | + app.get("*", (req, res) => { | ||
41 | + res.sendFile(path.resolve(__dirname, "../client", "build", "index.html")); | ||
42 | + }); | ||
43 | +} | ||
116 | 44 | ||
117 | app.listen(port, () => { | 45 | app.listen(port, () => { |
118 | - console.log(`Example app listening at http://localhost:${port}`) | ||
119 | -}) | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
46 | + console.log(`Server ---> http://localhost:${port}`) | ||
47 | +}); | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | -const { User } = require("../models/User"); | 1 | +const { User } = require('../models/User'); |
2 | 2 | ||
3 | let auth = (req, res, next) => { | 3 | let auth = (req, res, next) => { |
4 | // 인증 처리 | 4 | // 인증 처리 |
5 | // 1. client 쿠키에서 토큰을 가져옴. | 5 | // 1. client 쿠키에서 토큰을 가져옴. |
6 | - let token = req.cookies.loginCookie; | 6 | + let token = req.cookies.w_auth; |
7 | 7 | ||
8 | // 2. 토큰을 복호화한 후 유저를 찾는다. (User.js에 findByToken(); 있음) | 8 | // 2. 토큰을 복호화한 후 유저를 찾는다. (User.js에 findByToken(); 있음) |
9 | User.findByToken(token, (err, user)=>{ | 9 | User.findByToken(token, (err, user)=>{ |
... | @@ -15,9 +15,9 @@ let auth = (req, res, next) => { | ... | @@ -15,9 +15,9 @@ let auth = (req, res, next) => { |
15 | req.token = token; // token과 user를 request에 넣어줌으로써 index.js에서 request 사용할 수 있음 | 15 | req.token = token; // token과 user를 request에 넣어줌으로써 index.js에서 request 사용할 수 있음 |
16 | req.user = user; | 16 | req.user = user; |
17 | next(); | 17 | next(); |
18 | - }); | 18 | +}); |
19 | 19 | ||
20 | - // 3. 유저가 있으면 인증OK, 유저가 없으면 인증No! | 20 | +// 3. 유저가 있으면 인증OK, 유저가 없으면 인증No! |
21 | } | 21 | } |
22 | 22 | ||
23 | // 이 auth를 다른 파일에서도 쓸 수 있도록 | 23 | // 이 auth를 다른 파일에서도 쓸 수 있도록 | ... | ... |
... | @@ -5,35 +5,36 @@ const bcrypt = require('bcrypt') | ... | @@ -5,35 +5,36 @@ const bcrypt = require('bcrypt') |
5 | // bcrypt 사용하기 위해 salt를 생성하고 그걸 이용해 암호화 시킴 | 5 | // bcrypt 사용하기 위해 salt를 생성하고 그걸 이용해 암호화 시킴 |
6 | const saltRounds = 10 // salt를 몇글자 할 건지 | 6 | const saltRounds = 10 // salt를 몇글자 할 건지 |
7 | 7 | ||
8 | -// | 8 | +const jwt = require('jsonwebtoken'); |
9 | -const jwt = require('jsonwebtoken') | 9 | +const moment = require("moment"); |
10 | 10 | ||
11 | const userSchema = mongoose.Schema({ | 11 | const userSchema = mongoose.Schema({ |
12 | - name:{ | 12 | + name: { |
13 | - type: String, | 13 | + type:String, |
14 | - maxlength: 50 | 14 | + maxlength:50 |
15 | }, | 15 | }, |
16 | - email:{ | 16 | + email: { |
17 | - type: String, | 17 | + type:String, |
18 | - trim: true, // 'minjeong park'처럼 space가 있는 문자에 space가 없어지도록 함 | 18 | + trim:true, |
19 | - unique: 1 // 똑같은 이메일은 쓸 수 없도록 | 19 | + unique: 1 |
20 | }, | 20 | }, |
21 | password: { | 21 | password: { |
22 | type: String, | 22 | type: String, |
23 | - minlength: 5 | 23 | + minglength: 3 |
24 | }, | 24 | }, |
25 | lastname: { | 25 | lastname: { |
26 | - type: String, | 26 | + type:String, |
27 | maxlength: 50 | 27 | maxlength: 50 |
28 | }, | 28 | }, |
29 | - role: { // Number==1 이면 관리자, number==0 이면 일반 유저 | 29 | + role : { |
30 | - type: Number, | 30 | + type:Number, // Number==1 이면 관리자, number==0 이면 일반 유저 |
31 | default: 0 // default는 0 | 31 | default: 0 // default는 0 |
32 | }, | 32 | }, |
33 | + image: String, | ||
33 | token : { | 34 | token : { |
34 | - type : String | 35 | + type: String, |
35 | }, | 36 | }, |
36 | - tokenExp: { //토큰의 유효기간 | 37 | + tokenExp :{ |
37 | type: Number | 38 | type: Number |
38 | } | 39 | } |
39 | }) | 40 | }) |
... | @@ -41,11 +42,11 @@ const userSchema = mongoose.Schema({ | ... | @@ -41,11 +42,11 @@ const userSchema = mongoose.Schema({ |
41 | // index.js의 app.post('/register', (req, res)에 있는 | 42 | // index.js의 app.post('/register', (req, res)에 있는 |
42 | // user model에 user 정보를 저장하기 전에 무엇을 한다는 것 | 43 | // user model에 user 정보를 저장하기 전에 무엇을 한다는 것 |
43 | // function( next )를 해서 얘네가 끝난 다음에 다음걸 실행해라~ | 44 | // function( next )를 해서 얘네가 끝난 다음에 다음걸 실행해라~ |
44 | -userSchema.pre('save', function( next ){ | 45 | +userSchema.pre('save', function( next ) { |
45 | - var user = this | 46 | + var user = this; |
47 | + | ||
48 | + if(user.isModified('password')){ // password를 변경할 때만 적용되도록.. | ||
46 | 49 | ||
47 | - if(user.isModified('password')) // password를 변경할 때만 적용되도록.. | ||
48 | - { | ||
49 | // 비밀번호 암호화 (https://www.npmjs.com/package/bcrypt 에서 가져옴) | 50 | // 비밀번호 암호화 (https://www.npmjs.com/package/bcrypt 에서 가져옴) |
50 | bcrypt.genSalt(saltRounds, (err, salt) => // salt를 만드는 함수 | 51 | bcrypt.genSalt(saltRounds, (err, salt) => // salt를 만드는 함수 |
51 | { | 52 | { |
... | @@ -54,17 +55,14 @@ userSchema.pre('save', function( next ){ | ... | @@ -54,17 +55,14 @@ userSchema.pre('save', function( next ){ |
54 | if(err) return next(err) // 에러 나면 return err | 55 | if(err) return next(err) // 에러 나면 return err |
55 | user.password = hash // 성공하면 user.password를 hash로 교체 | 56 | user.password = hash // 성공하면 user.password를 hash로 교체 |
56 | next() | 57 | next() |
57 | - }); | 58 | + }) |
58 | - }); | 59 | + }) |
59 | - } | 60 | + } else { |
60 | - else | ||
61 | - { | ||
62 | next() | 61 | next() |
63 | } | 62 | } |
63 | +}); | ||
64 | 64 | ||
65 | -}) | 65 | +userSchema.methods.comparePassword = function(plainPassword,cb){ |
66 | - | ||
67 | -userSchema.methods.comparePassword = function(plainPassword, cb){ | ||
68 | 66 | ||
69 | // 1. plainPassword가 1234567 암호화된 비밀번호 가 같은지 체크해야함 | 67 | // 1. plainPassword가 1234567 암호화된 비밀번호 가 같은지 체크해야함 |
70 | // 그러면 plainPassword도 암호화해서 비교해야함. (복호화 할 수 없기 때문에) | 68 | // 그러면 plainPassword도 암호화해서 비교해야함. (복호화 할 수 없기 때문에) |
... | @@ -75,23 +73,21 @@ userSchema.methods.comparePassword = function(plainPassword, cb){ | ... | @@ -75,23 +73,21 @@ userSchema.methods.comparePassword = function(plainPassword, cb){ |
75 | }) | 73 | }) |
76 | } | 74 | } |
77 | 75 | ||
78 | -userSchema.methods.generateToken = function(cb) | 76 | +userSchema.methods.generateToken = function(cb) { |
79 | -{ | ||
80 | var user = this; | 77 | var user = this; |
81 | // jsonwebtoken을 이용해서 token 생성 | 78 | // jsonwebtoken을 이용해서 token 생성 |
82 | var token = jwt.sign(user._id.toHexString(), 'secretToken') //database에 있는 id라서 _id | 79 | var token = jwt.sign(user._id.toHexString(), 'secretToken') //database에 있는 id라서 _id |
80 | + var oneHour = moment().add(1, 'hour').valueOf(); | ||
83 | 81 | ||
84 | - user.token = token | 82 | + user.tokenExp = oneHour; |
85 | - user.save(function(err, user){ | 83 | + user.token = token; |
86 | - if(err) | 84 | + user.save(function (err, user){ |
87 | - return cb(err) // 에러가 있다면 callback으로 에러 전달 | 85 | + if(err) return cb(err)// 에러가 있다면 callback으로 에러 전달 |
88 | cb(null, user) // 에러가 없다면 err는 없고 user정보만 전달 | 86 | cb(null, user) // 에러가 없다면 err는 없고 user정보만 전달 |
89 | }) | 87 | }) |
90 | - | ||
91 | } | 88 | } |
92 | 89 | ||
93 | -userSchema.statics.findByToken = function(token, cb) | 90 | +userSchema.statics.findByToken = function (token, cb) { |
94 | -{ | ||
95 | var user = this; | 91 | var user = this; |
96 | 92 | ||
97 | // 1. 토큰을 decoding | 93 | // 1. 토큰을 decoding |
... | @@ -103,11 +99,9 @@ userSchema.statics.findByToken = function(token, cb) | ... | @@ -103,11 +99,9 @@ userSchema.statics.findByToken = function(token, cb) |
103 | // 에러가 안나면 | 99 | // 에러가 안나면 |
104 | cb(null, user) | 100 | cb(null, user) |
105 | }) | 101 | }) |
106 | - }) | 102 | +}) |
107 | } | 103 | } |
108 | 104 | ||
109 | -// 만든 스키마를 모델로 감싸줌 | 105 | +const User = mongoose.model('User', userSchema); |
110 | -const User = mongoose.model('User', userSchema) | ||
111 | 106 | ||
112 | -// 이 모델을 다른 파일에서도 쓰고싶으면 아래와 같이 해주면 됨 | ||
113 | -module.exports = {User} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
107 | +module.exports = { User } | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
We-Shop/server/routes/users.js
0 → 100644
1 | +const express = require('express'); | ||
2 | +const { User } = require("../models/User"); | ||
3 | +const { auth } = require("../middleware/auth"); | ||
4 | +const router = express.Router(); | ||
5 | + | ||
6 | +router.get("/auth", auth, (req, res) => { | ||
7 | + res.status(200).json({ | ||
8 | + _id: req.user._id, | ||
9 | + isAdmin: req.user.role === 0 ? false : true, | ||
10 | + isAuth: true, | ||
11 | + email: req.user.email, | ||
12 | + name: req.user.name, | ||
13 | + lastname: req.user.lastname, | ||
14 | + role: req.user.role, | ||
15 | + image: req.user.image, | ||
16 | + }); | ||
17 | +}); | ||
18 | + | ||
19 | +router.post("/register", (req, res) => { | ||
20 | + | ||
21 | + const user = new User(req.body); | ||
22 | + | ||
23 | + user.save((err, doc) => { | ||
24 | + if (err) return res.json({ success: false, err }); | ||
25 | + return res.status(200).json({ | ||
26 | + success: true | ||
27 | + }); | ||
28 | + }); | ||
29 | +}); | ||
30 | + | ||
31 | +router.post("/login", (req, res) => { | ||
32 | + User.findOne({ email: req.body.email }, (err, user) => { | ||
33 | + if (!user) | ||
34 | + return res.json({ | ||
35 | + loginSuccess: false, | ||
36 | + message: "Auth failed, email not found" | ||
37 | + }); | ||
38 | + | ||
39 | + user.comparePassword(req.body.password, (err, isMatch) => { | ||
40 | + if (!isMatch) | ||
41 | + return res.json({ loginSuccess: false, message: "Wrong password" }); | ||
42 | + | ||
43 | + user.generateToken((err, user) => { | ||
44 | + if (err) return res.status(400).send(err); | ||
45 | + res.cookie("w_authExp", user.tokenExp); | ||
46 | + res | ||
47 | + .cookie("w_auth", user.token) | ||
48 | + .status(200) | ||
49 | + .json({ | ||
50 | + loginSuccess: true, userId: user._id | ||
51 | + }); | ||
52 | + }); | ||
53 | + }); | ||
54 | + }); | ||
55 | +}); | ||
56 | + | ||
57 | +router.get("/logout", auth, (req, res) => { | ||
58 | + User.findOneAndUpdate({ _id: req.user._id }, { token: "", tokenExp: "" }, (err, doc) => { | ||
59 | + if (err) return res.json({ success: false, err }); | ||
60 | + return res.status(200).send({ | ||
61 | + success: true | ||
62 | + }); | ||
63 | + }); | ||
64 | +}); | ||
65 | + | ||
66 | +module.exports = router; |
-
Please register or login to post a comment