본문 바로가기
Web/Node.js

14. Postman 정리, 아이디 중복체크

by 사라리24 2024. 5. 2.
SMALL

 

1.  Postman 정리

  

 

 

  • postman _ collection 추가

 

 

  • postman _ collection_request 추가

 

 

 

1-1. 모든 트윗 가져오기

더보기
주소확인

 

 

 

1-2. 해당 아이디에 대한 트윗 가져오기

  

 

 

 

1-3.  해당 이름에 대한 트윗 가져오기

  

 

 

 

1-4.  트윗 생성하기

  

 

 

 

1-5.   트윗 수정하기

  

 

 

 

1-6.   트윗 삭제하기

  

 


 

2-1. 회원가입하기

  

 

 

 

2-2. 로그인하기

  

 

 

 

2-3. 나 확인하기

  


 

  • 폴더정리하기

 

 


 

 

2.  문제

  회원가입시 아이디 중복체크 하기
  단, 중복이라면 409를 리턴

 

  • data > auth.js 추가
  
      < data > auth.js >

                {
                    id: '2',
                    username: "banana",
                    password: "$2b$10$/4lYMMsFC6rBSxlI1/qP5uwROuFZMtALVttv/2TbQ0bJXIFGeqPXe",
                    name: "반하나",
                    email: "banana@banana.com",
                }
 
 
       </ data >  auth.js  >
  

 

  • data > auth.js 추가
 
     < data > auth.js >

 
            //아이디 중복검사
            export async function findByUsername(username){
                return users.find((user) => user.username === user.username);
            }
 
            //id 중복검사
            export async function findByid(id){
                return users.find((user) => user.id === id);
            }
 
 
      </ data >  auth.js  >
  

 

  • controllar > auth.js 수정
  
      < controllar > auth.js >

            // 회원가입 함수 //수정
            export async function signup(req, res, next){
                const { username, password, name, email, url } = req.body;
                const found = await authRepository.findByUsername(username); //found 추가
                if(found){ //if 추가
                    return res.status(409).json({message:`${username}이 이미 있습니다`})
                }
                const hashed = await bcrypt.hash(password, bcryptSaltRounds); //추가
                const userId = await authRepository.createUser({username, hashed, password,name, email, url});  
                //중괄호로 user 객체로 받기
                const token = createJwtTodken(userId); //토큰 추가
                res.status(201).json({token, username}); //if문 삭제
                        }
 
       < /controllar> auth.js  >
  
 

 

  • data > auth.js 추가
  
      <  data > auth.js >

            export async function createUser(user){ //매개변수 변경
                const created = {id:'10', ... user} //created 정의
                // const user ={
                //     id: "10",
                //     username,
                //     password,
                //     name,
                //     email,
                // }
                users.push(created) //push
                return created.id;
            }

       </  data > auth.js  >
  
 
url 추가
h



 

 


  • controllar > auth.js 수정
 
      < controllar> auth.js >

            // 로그인하는 함수
            export async function login(req, res, next){
                const { username, password } = req.body;
                // const user = await authRepository.login(username); //삭제
                const user = await authRepository.findeByUsername(username);
                if(!user){
                    return res.status(401).json({message: `아이디를 찾을 수 없음`});
                }
                const isValidpassword = await bcrypt.compareSync(password, user.password);
                if(!isValidpassword){
                    return res.status(401).json({message: `비밀번호가 틀렸음`});
                }
                const token = createJwtTodken(user,id);
                res.status(200).json({token, username});
            }
                    // if(bcrypt.compareSync(password, user.password)){
                    //     //res.status(201).json(`${username} 로그인 완료`); //지우기
                    //     res.status(201).header('Token', makeToken(username)).json(`${username} 로그인 완료`); //토큰값만들기 //추가
                    // }
                    // else{
                    //     res.status(404).json({message: `${username}님 아이디 또는 비밀번호 확인하세요`})
                    // }
                // }else{
                //      res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
                // }
 
       </ controllar> auth.js   >
  

 

 

 


 

 

 

  • postman에서 Authorization:Bearer 등록

 

  • controllar > auth.js 삭제 추가
  
  
     < controllar > auth.js   >

            //토큰 확인 삭제
            //export async function verify(req, res, next){
            //    const token = req.header['Token'];
            //    if(token){
            //        res.status(200).json(token);
            //   }
            //}

            //me 추가
            export async function me(req, res, next){
                const user = await authRepository.findById(req.userId);
                if(!user){
                    return res.status(404).json({message: `일치하는 사용자가 없음`});
                }
                res.status(200).json({token: req.token, username: user.username});
            }
 
      < /controllar> auth.js   >
  
 

 

 

  • middleware  > auth.js 생성
 
 
      <  middleware  > auth.js  >
 
            import jwt from 'jsonwebtoken';
            import * as authRepository from '../data/auth.js';

            const AUTH_ERROR = {message: "인증에러"};

            export const isAuth = async(req, res, next) => {
                const authHeader = req.get('Authorization');
                console.log(authHeader);
            }

 
       </ middleware  > auth.js   >
  
 

 

  • router  > auth.js 수정
  
      < router > auth.js >

            import express from 'express';
            import { body } from 'express-validator';
            import * as authController from '../controller/auth.js';
            import { validate } from '../middleware/validator.js';
            import { isAuth } from '../middleware/auth.js'; //추가

            const router = express.Router();

            const validateSignup = [
                body('username').trim().isLength({ min: 3 }).withMessage('최소 3자 이상 입력'),
                body('password').trim().isLength({ min: 4 }).withMessage('최소 4자 이상 입력'),
                body('email').trim().isEmail().withMessage('이메일 형식 확인'),
                validate
            ]

            router.post('/signup', validateSignup, authController.signup);

            router.post('/login', authController.login);

            router.get('/me', isAuth, authController.me); //수정

            export default router;
 
       </ router > auth.js   >
  
 

[console 창]
토큰이 찍힘



 

 

 


 

 

  • middleware  > auth.js 수정
  
 
      <  middleware  > auth.js  >

            import jwt from 'jsonwebtoken';
            import * as authRepository from '../data/auth.js';
            const AUTH_ERROR = {message: "인증에러"};
            export const isAuth = async (req, res, next) => {
                const authHeader = req.get('Authorization');
                console.log(authHeader);
                if(!(authHeader && authHeader.startsWith('Bearer '))){
                    console.log('에러1');
                    return res.status(401).json(AUTH_ERROR);
                }
                const token = authHeader.split(' ')[1];
                jwt.verify(
                    token, 'abcd1234%^&*', async(error, decoded) => {
                        if(error){
                            console.log('에러2');
                            return res.status(401).json(AUTH_ERROR);
                        }
                        const user = await authRepository.findById(decoded.id);
                        if(!user){
                            console.log('에러3');
                            return res.status(401).json(AUTH_ERROR);
                        }
                        req.userId = user.id;
                        next();
                    }
                );
            }

 
      </ middleware  > auth.js  >
  
 





 


  • router  > auth.js 수정
 
      < router > auth.js >

            import express from 'express';
            import { body } from 'express-validator';
            import * as authController from '../controller/auth.js';
            import { validate } from '../middleware/validator.js';
            import { isAuth } from '../middleware/auth.js';  //추가

            const router = express.Router();

            //추가
            const validateLogin = [
                body('username').trim().notEmpty().withMessage('username을 입력하세요'),
                body('password').trim().isLength({ min: 4 }).withMessage('password는 최소 4자 이상 입력하세요'), validate

            ];

            //수정
            const validateSignup = [
                ...validateLogin,
                body('name').trim().notEmpty().withMessage('최소 3자 이상 입력'),
                body('email').isEmail().withMessage('이메일 형식을 확인하세요'),
                body('url').isURL().withMessage('URL 형식을 입력하세요'),
                validate
            ];


            router.post('/signup', validateSignup, authController.signup);

            router.post('/login', validateSignup, authController.login);  //수정

            router.get('/me', isAuth, authController.me);

            export default router;
 
       </router > auth.js >
  




 

  • router > tweets
 
      < router > tweets >

            import express from "express";
            import * as tweetController from '../controller/tweet.js';
            import { body } from 'express-validator';
            import { validate } from "../middleware/validator.js";
            import { isAuth } from "../middleware/auth.js" /추가

            const router = express.Router();

            /*
                Post, Put에 text에 대해 빈문자열을 없애고, 최소 3자 이상 입력해야 데이터를 저장하도록 API에 적용
            */
            const validateTweet = [
                body('text').trim().isLength({min: 3}).withMessage('최소 3자 이상 입력'), validate
            ]


            // 해당 아이디에 대한 트윗 가져오기
            // GET
            // http://localhost:8080/tweets?username=:username
            router.get('/', isAuth, tweetController.getTweets);  /isAuth추가


            // 글번호에 대한 트윗 가져오기
            // GET
            // http://localhost:8080/tweets/:id
            router.get('/:id', isAuth, tweetController.getTweet); /isAuth추가


            // 트윗하기
            // POST
            // http://localhost:8080/tweets
            // name, username, text
            // json 형태로 입력 후 추가된 데이터까지 모두 json으로 출력
            router.post('/', isAuth, validateTweet, tweetController.createTweet); /isAuth추가


            // 트윗 수정하기
            // PUT
            // http://localhost:8080/tweets/:id
            // id, username, text
            // json 형태로 입력 후 변경된 데이터까지 모두 json으로 출력
            router.put('/:id', isAuth, validateTweet, tweetController.updateTweet); /isAuth추가


            // 트윗 삭제하기
            // DELETE
            // http://localhost:8080/tweets/:id
            router.delete('/:id', isAuth, tweetController.deleteTweet); /isAuth추가

            export default router;

       </ router > tweets  >
  
 




 
 






 

 

 

❗ 전체코드

  • controllar 폴더
더보기
  • auth.js
 
 
            import * as authRepository from '../data/auth.js';
            import bcrypt from 'bcrypt';
            import jwt from 'jsonwebtoken';
            import { config } from '../config.js'; //추가

            //삭제
            //const secretKey = "abcd1234%^&*" ;
            //const jwtExpiresInDays = '2d';
            //const bcryptSaltRounds = 10;


            // jwt 토근생성 //수정
            function createJwtToken(id){
                return jwt.sign({id}, config.jwt.secretKey, {expiresIn: config.jwt.expiresInSec});
            }

            // 회원가입 함수
            export async function signup(req, res, next){
                const {username, password, name, email, url} = req.body;
                const found = await authRepository.findByUsername(username);
                if(found){
                    return res.status(409).json({message:`${username}이 이미 있습니다`});
                }
                const hashed = await bcrypt.hash(password, config.bcrypt.saltRounds); //수정
                const userId = await authRepository.createUser({username, hashed, name, email, url});
                const token = createJwtToken(userId);
                res.status(201).json({token, username});
            }
           
            // 로그인하는 함수
            export async function login(req, res, next){
                const {username, password} = req.body;
                const user = await authRepository.findByUsername(username);
                if(!user){
                    return res.status(401).json({message : '아이디를 찾을 수 없음'})
                }
                const isValidpassword = await bcrypt.compareSync(password, user.password);
                if(!isValidpassword){
                    return res.status(401).json({message : `비밀번호가 틀렸음`});
                }
                const token = createJwtToken(user.id);
                    return res.status(200).json({token, username});
            }

            //me
            export async function me(req, res, next){
                const user = await authRepository.findById(req.userId);
                if(!user){
                    return res.status(404).json({message: `일치하는 사용자가 없음`});
                }
                res.status(200).json({token: req.token, username: user.username});
            }
 

 

  • tweets.js
 
 
            import * as tweetRepository from '../data/tweet.js';

            // 여러 트윗을 가져오는 함수
            export async function getTweets(req, res){
                const username = req.query.username;
                const data = await (username ? tweetRepository.getAllByUsername(username)
                                            : tweetRepository.getAll());
                res.status(200).json(data);
            }

            // 하나의 트윗을 가져오는 함수
            export async function getTweet(req, res, next) {
                const id = req.params.id;
                const tweet = await tweetRepository.getById(id);
                if(tweet){
                    res.status(200).json(tweet);
                }else{
                    res.status(404).json({message: `${id}의 트윗이 없습니다`})
                }
            }

            // 트윗을 생성하는 함수
            export async function createTweet(req, res, next) {
                const {text, name, username} = req.body;
                const tweet = await tweetRepository.create(text, name, username);
                res.status(201).json(tweet);
            }

            // 트윗을 변경하는 함수
            export async function updateTweet(req, res, next) {
                const id = req.params.id;
                const text = req.body.text;
                const tweet = await tweetRepository.update(id, text);
                if(tweet){
                    res.status(201).json(tweet);
                }else{
                    res.status(404).json({message: `${id}의 트윗이 없습니다`})
                }
            }

            // 트윗을 삭제하는 함수
            export async function deleteTweet(req, res, next) {
                const id = req.params.id;
                await tweetRepository.remove(id);
                res.sendStatus(204);
            }
 
 

 

 

  • data 폴더
더보기
  • auth.js
 
 
            let users = [
                {
                    id: '1',
                    username: "apple",
                    password: "$2b$10$/4lYMMsFC6rBSxlI1/qP5uwROuFZMtALVttv/2TbQ0bJXIFGeqPXe",
                    name: "김사과",
                    email: "apple@apple.com",
                },
               
                {
                    id: '2',
                    username: "banana",
                    password: "$2b$10$/4lYMMsFC6rBSxlI1/qP5uwROuFZMtALVttv/2TbQ0bJXIFGeqPXe",
                    name: "반하나",
                    email: "banana@banana.com",
                }
            ];



            //아이디 중복검사
            export async function findByUsername(username){
                return users.find((user) => user.username === user.username);
            }

            //id 중복검사
            export async function findById(id){
                return use.find((user) => user.id === id);
            }


            export async function createUser(user){ //매개변수 변경
                const created = {ud:'10', ... user} //created 정의
                // const user ={
                //     id: "10",
                //     username,
                //     password,
                //     name,
                //     email,
                // }
                users.push(created) //push
                return created.id;
            }

            export async function login(username){
                return users.find((users) => users.username === username);
            }
 
 
  • tweets.js
 
 
            let tweets = [
                {
                    id: '1',
                    text: '안녕하세요!',
                    createdAt: Date.now().toString(),
                    name: '김사과',
                    username: 'apple',
                },
                {
                    id: '2',
                    text: '반갑습니다!',
                    createdAt: Date.now().toString(),
                    name: '반하나',
                    username: 'banana',
                }
            ];

            // 모든 트윗을 리턴
            export async function getAll() {
                return tweets;
            }

            // 해당 아이디에 대한 트윗을 리턴
            export async function getAllByUsername(username){
                return tweets.filter((tweet) => tweet.username === username)
            }

            // 글번호에 대한 트윗을 리턴
            export async function getById(id){
                return tweets.find((tweet) => tweet.id === id);
            }

            // 트윗을 작성
            export async function create(text, name, username){
                const tweet = {
                    id: '10',
                    text,
                    createdAt: Date.now().toString(),
                    name,
                    username
                };
                tweets = [tweet, ...tweets];
                return tweets;
            }

            // 트윗을 변경
            export async function update(id, text){
                const tweet = tweets.find((tweet) => tweet.id === id);
                if(tweet){
                    tweet.text = text;
                }
                return tweet;
            }

            // 트윗을 삭제
            export async function remove(id){
                tweets = tweets.filter((tweet) => tweet.id !== id);
            }
 
 

 

 

  • middleware 폴더
더보기
  • auth.js
 
 
            import jwt from 'jsonwebtoken';
            import * as authRepository from '../data/auth.js';
            const AUTH_ERROR = {message: "인증에러"};
            export const isAuth = async (req, res, next) => {
                const authHeader = req.get('Authorization');
                console.log(authHeader);
                if(!(authHeader && authHeader.startsWith('Bearer '))){
                    console.log('에러1');
                    return res.status(401).json(AUTH_ERROR);
                }
                const token = authHeader.split(' ')[1];
                jwt.verify(
                    token, 'abcd1234%^&*', async(error, decoded) => {
                        if(error){
                            console.log('에러2');
                            return res.status(401).json(AUTH_ERROR);
                        }
                        const user = await authRepository.findById(decoded.id);
                        if(!user){
                            console.log('에러3');
                            return res.status(401).json(AUTH_ERROR);
                        }
                        req.userId = user.id;
                        next();
                    }
                );
            }
 
 
  • validator.js
 
 
            import { validationResult } from 'express-validator';

            export const validate = (req, res, next) => {
                const errors = validationResult(req);
                if(errors.isEmpty()){
                    return next();
                }
                return res.status(400).json({message:errors.array()[0].msg})
            }
 
 

 

  • router 폴더
더보기
  • auth.js
 
 
            import express from 'express';
            import { body } from 'express-validator';
            import * as authController from '../controller/auth.js';
            import { validate } from '../middleware/validator.js';
            import { isAuth } from '../middleware/auth.js';  //추가

            const router = express.Router();

            //추가
            const validateLogin = [
                body('username').trim().notEmpty().withMessage('username을 입력하세요'),
                body('password').trim().isLength({ min: 4 }).withMessage('password는 최소 4자 이상 입력하세요'), validate

            ];

            //수정
            const validateSignup = [
                ...validateLogin,
                body('name').trim().notEmpty().withMessage('name을 입력하세요'),
                body('email').isEmail().withMessage('이메일 형식을 확인하세요'),
                body('url').isURL().withMessage('URL 형식을 입력하세요'),
                validate
            ];


            router.post('/signup', validateSignup, authController.signup);

            router.post('/login', validateSignup, authController.login);  //수정

            router.get('/me', isAuth, authController.me);

            export default router;
 
 
  • tweets.js
 
 
            import express from "express";
            import * as tweetController from '../controller/tweet.js';
            import { body } from 'express-validator';
            import { validate } from "../middleware/validator.js";
            import { isAuth } from "../middleware/auth.js"

            const router = express.Router();

            /*
                Post, Put에 text에 대해 빈문자열을 없애고, 최소 3자 이상 입력해야 데이터를 저장하도록 API에 적용
            */
            const validateTweet = [
                body('text').trim().isLength({min: 3}).withMessage('최소 3자 이상 입력'), validate
            ]


            // 해당 아이디에 대한 트윗 가져오기
            // GET
            // http://localhost:8080/tweets?username=:username
            router.get('/', isAuth, tweetController.getTweets);


            // 글번호에 대한 트윗 가져오기
            // GET
            // http://localhost:8080/tweets/:id
            router.get('/:id', isAuth, tweetController.getTweet);


            // 트윗하기
            // POST
            // http://localhost:8080/tweets
            // name, username, text
            // json 형태로 입력 후 추가된 데이터까지 모두 json으로 출력
            router.post('/', validateTweet, isAuth, tweetController.createTweet);


            // 트윗 수정하기
            // PUT
            // http://localhost:8080/tweets/:id
            // id, username, text
            // json 형태로 입력 후 변경된 데이터까지 모두 json으로 출력
            router.put('/:id', validateTweet, isAuth, tweetController.updateTweet);


            // 트윗 삭제하기
            // DELETE
            // http://localhost:8080/tweets/:id
            router.delete('/:id', isAuth, tweetController.deleteTweet);

            export default router;
 
 
 

 

  • app.js
더보기


            import express from "express";
            import morgan from "morgan";
            import tweetsRouter from './router/tweets.js';
            import authRouter from './router/auth.js';
            import { config } from './config.js'; //추가

            const app = express();

            app.use(express.json());
            app.use(morgan("dev"));

            app.use('/tweets', tweetsRouter);  
            app.use('/auth', authRouter);

            app.use((req, res, next) => {
                res.sendStatus(404);
            });

            //app.listen(8080);//삭제
            app.listen(config.host.port);//추가
 
 

 

  • bycrpt.js
더보기
 
 
            import * as bcrypt from "bcrypt";

            const password = 'abcd1234';
            const hashed = bcrypt.hashSync(password, 10)
            //hashSync(매개변수, 솔트값) // 솔트값: 숫자가 높을 수록 속도가 느림 // 10이하 추천
            console.log(`password: ${password}, hashed: ${hashed}`);


            const result = bcrypt.compareSync('abcd1234',hashed);
            console.log(result);
   
 
 

 

  • config.js
더보기
 
 
 
            import dotenv from 'dotenv';

            dotenv.config();

            function required(key, defaultValue=undefined){
                const value = process.env[key] || defaultValue
                // process.env() : 시스템에 접근 관련한 모듈
                // env 다룰 수 있는 기능이 들어있음
                // 먼저 전달받은 키가 있는지 확인,
                // or 앞의 값이 True로 판별되면 앞의 값이 대입,
                // or 앞의 값이 False로 판별되면 뒤의 값이 대입
                if(value == null){
                    throw new Error(`키 ${key}는 undefined!!`);
                }
                return value;
            }

            //외부에서 가져다 쓸 수 있게 작성
            export const config = {
                jwt: {
                    secretKey: required('JWT_SECRET'),
                    expiresInSec: parseInt(required('JWT_EXPIRES_SEC', 172800))
                },
                bcrypt: {
                    saltRounds: parseInt(required('BCRYPT_SALT_ROUNDS', 10))
                },
                host: {
                    port: parseInt(required('HOST_PORT', 8080))
                }
            }
 
 

 

  • jwt.js
더보기
 
 
            import jwt from 'jsonwebtoken';

            const secret='abcdefg1234%^&*';

            const token = jwt.sign(
                {
                    id:'apple',
                    isAdmin:false
                },
                secret,
                {expiresIn: "1h"} // 얼마만큼 토근이 유지될 것인가
            );

            //expiresIn: "1h"
            //expiresIn: 2 유지되다 에러

            setTimeout(()=>{
                jwt.verify(token,secret,(error,decoded)=>{
                    console.log(error,decoded);
                });
            }, 3000); // 3초마다 찍어주기

            console.log(token);

            // 일단 토큰찍고 4초 뒤에 set timeout에서 토큰, 시크릿 확인해보니 에러
            // (4초 지나서 만료시간 지남 jwt expired)
            // 2초로 바꾸면 decoded 잘 뜸
 
 
 

 

  • validation.js
더보기
 
 
 
 
            import express from 'express';
            import { body, param, validationResult } from "express-validator";

            const app = express();
            app.use(express.json());

            const validate = (req, res, next) => {
                const errors = validationResult(req);
                if(errors.isEmpty()){
                    return next();
                }
                console.log(errors.array());
                return res.status(400).json({message: errors.array()[0].msg});
            }

            app.get('/:email', [param('email').isEmail().withMessage('이메일을 입력하세요!'), validate], (req, res, next) => {
                res.send(':연애편지:');
            });


            //[]: validation 기능을 안에다 쓸 수 있다
            // 메서드 체이닝으로 벨리데이션 쓰기
            // trim: 공백 없애기
            // isLength: 최대최소 설정
            // post: 자료를 bbody로 받음
            // get: param로 받음

            app.post('/users', [
                body('name').trim().isLength({min:2}).withMessage('이름은 두글자 이상으로 입력!'),
                body('age').isInt().withMessage('나이는 숫자로 입력!'),
                body('height').isInt({min:100, max:200}).withMessage('키는 100이상 200이하로 입력하세요!'),
                body('job').notEmpty(),
                validate
            ], (req, res, next) => {
                console.log(req.body);
                res.sendStatus(201);
            })

            app.listen(8080);
 
 

 

 

'Web > Node.js' 카테고리의 다른 글

16. ORM  (0) 2024.05.03
15. 환경변수, 웹소켓  (0) 2024.05.03
13. Authentication, bcrypt, JWT  (0) 2024.04.29
12. Validate(데이터 검증)  (0) 2024.04.29
11. 리팩토링  (0) 2024.04.26