회원가입과 로그인 구현

이재경·2022년 12월 28일
0

백엔드

목록 보기
5/7

1.비밀번호 hash

(1)SHA1-사용방법

Node.js의 기본제공 모듈인 crypto 모듈을 사용하여 hash값을 얻을 수 있음
간단하게 sha1 알고리즘을 사용하거나
보다 강력한 sha224,sha256등의 알고리즘도 사용할수 있음

2.회원가입 구현

회원가입 페이지 구현 -> script를 이요해 이메일 형식, 비밀번호 확인 문자 확인 -> form을 이용해 post 요청 전송 -> 회원가입 처리 및 redirect

3.회원가입 요청 처리하기


비밀번호 hash값 저장
이미 존재하는 회원인지 체크
가입 후 메인화면으로 redirect

4.회원가입 구현하기(코드)

hash-password.js

const crypto = require('crypto');

module.exports = (password) => {
  const hash = crypto.createHash('sha1');
  hash.update(password);
  return hash.digest("hex");
}

index.js

const { Router } = require('express');
const asyncHandler = require('../utils/async-handler');
const { User } = require('../models');
const hashPassword=require('../utils/hash-password')
const router = Router();

router.get('/', (req, res) => {
  if(req.user) {
    res.redirect('/posts');
    return;
  }
  
  res.redirect('/login');
});

router.get('/login', (req, res, next) => {
  res.render('user/login');
});

router.get('/join', (req, res, next) => {
  res.render('user/join');
});

router.post('/join', asyncHandler(async (req, res) => {
  const { email, name, password } = req.body;
  const hashedPassword =hashPassword(password)
  
   // 비밀번호 해쉬값 만들기
  const user = await User.create({
      email,
      name,
      password:hashedPassword
  })
  
  
  // 회원 생성하기
  
  // 아래 코드 수정 시 오답으로 처리될 수 있습니다.
  console.log('신규 회원', user);
  
  res.redirect('/');
}));

module.exports = router;

app.js

const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const mongoose = require('mongoose');
const dayjs = require('dayjs');

const indexRouter = require('./routes');
const postsRouter = require('./routes/posts');

mongoose.connect('mongodb://localhost:27017/simple-board');

mongoose.connection.on('connected', () => {
  console.log('MongoDB Connected');
});

const app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.locals.formatDate = (date) => {
  return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
}

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/posts', postsRouter);

// catch 404 and forward to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// error handler
app.use((err, req, res, next) => {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

5.로그인 구현


(1)possport-local strategy

(2)passport.js 설정-passport.use

작성한 strategy를 possport.use를 이용해 사용하도록 선언해야 함
possport.use를 이용해 strategy를 사용하도록 선언한 후 possport.authenticate를 사용해 해당 strategy를 이용해 요청을 처리할 수 있음

(3)passport.js로 post 요청 처리하기

passport.authenticate 함수http 라우팅에 연결하면 possport가 자동으로 해당하는 strategy를 사용하는 request handler를 자동 생성
express-session과 possport.session()을 사용하면 passport가 로그인 시 유저 정보를 세션에 저장하고 가져오는 동작을 자동으로 수행해줌

(4)session 유저 활용하기

session을 이용해 user를 사용할 때에는 serializeUserdeserializeUser를 설정해 주어야 함
이는 세션에 user 정보를 변환하여 저장하고 가져오는 기능을 제공
ex)회원 id만 세션에 저장하고, 사용 시 회원 정보를 디비에서 찾아서 사용

*세션 사용 시 위 두 함수를 작성하지 않으면 passport 로그인이 동작하지 않음

(5)로그아웃

possport는 req.logout 함수를 통해 세션의 로그인 정보를 삭제하여, 로그아웃 기능 구현

(6)로그인 확인 미들웨어

로그인을 필수로 설정하고 싶을 경우, 미들웨어를 사용하여 체크할수 있음

6.로그인 구현하기(코드)

local.js

const LocalStrategy = require('passport-local').Strategy;
const { User } = require('../../models');
const hashPassword = require('../../utils/hash-password');

const config = {
  usernameField:'email',
  passwordField:'password'
};

const local = new LocalStrategy(config, async (email, password, done) => {
  try {
    const user = await User.findOne({ email });
    if (!user) {
      throw new Error('회원을 찾을 수 없습니다.');
    }
    // 검색 한 유저의 비밀번호와 요청된 비밀번호의 해쉬값이 일치하는지 확인
    if (user.password!==hashPassword(password)) {
      throw new Error('비밀번호가 일치하지 않습니다.');
    }

    done (null, {
      shortId: user.shortId,
      email: user.email,
      name: user.name,
    });
  } catch (err) {
    done(err, null);
  }
});

module.exports = local;

index.js

const passport = require('passport');
const local=require('./strategies/local')
module.exports = () => {
  // local strategy 사용
passport.use(local)
  passport.serializeUser((user, callback) => {
    callback(null, user);
  });

  passport.deserializeUser((obj, callback) => {
    callback(null, obj);
  });
};

app.js

const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const mongoose = require('mongoose');
const dayjs = require('dayjs');
const session = require('express-session');
const passport = require('passport'); 

const indexRouter = require('./routes');
const postsRouter = require('./routes/posts');
const authRouter = require('./routes/auth');
const loginRequired=require('./middlewares/login-required')
require('./passport')();

mongoose.connect('mongodb://localhost:27017/simple-board');

mongoose.connection.on('connected', () => {
  console.log('MongoDB Connected');
});

const app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.locals.formatDate = (date) => {
  return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
}

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use(session({ 
  secret: 'elice', 
  resave: false, 
  saveUninitialized: true 
}));
// passport initialize
// passport session 
app.use(passport.initialize())
app.use(passport.session())
app.use('/', indexRouter);
// /posts 경로에 로그인 필수로 설정하기
app.use('/posts',loginRequired, postsRouter);
app.use('/auth', authRouter);

// catch 404 and forward to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// error handler
app.use((err, req, res, next) => {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

auth.js

const { Router } = require('express');
const passport = require('passport');

const router = Router();

// passport local 로 authenticate 하기
router.post('/', passport.authenticate('local'),(req, res, next) => {
  res.redirect('/');
});

module.exports = router;

routes/index.js

const { Router } = require('express');
const asyncHandler = require('../utils/async-handler');
const hashPassword = require('../utils/hash-password');
const { User } = require('../models');

const router = Router();

router.get('/', (req, res) => {

    if(req.user){
        res.redirect('/posts')
        return
    }
    res.redirect('/login')
    
  // 로그인 된 경우 /posts로 
  // 로그인 되지 않은 경우 /login 으로
});

router.get('/login', (req, res, next) => {
  res.render('user/login');
});

router.get('/join', (req, res, next) => {
  res.render('user/join');
});

router.post('/join', asyncHandler(async (req, res) => {
  const { email, name, password } = req.body;
  const hashedPassword = hashPassword(password);
  const user = await User.create({
    email,
    name,
    password: hashedPassword,
  });
  
  console.log('신규 회원', user);
  
  res.redirect('/');
}));

router.get('/logout', (req, res, next) => {
  req.logout();
  res.redirect('/');
});

module.exports = router;

middlewares/login-required.js

module.exports = (req, res, next) => {
  // 로그인이 안되어있다면 메인화면으로
  // 로그인이 되어있다면 다음 미들웨어로
if(!req.user){
    res.redirect('/')
    return
}
next()


  
}
profile
코딩으로 빛나게

0개의 댓글