티스토리 뷰

Passport

 

로컬 로그인 뿐만아니라 소셜 로그인에서까지 쉽게 인증이 가능한 미들웨어이다.

http://www.passportjs.org/

 

Passport.js

Simple, unobtrusive authentication for Node.js

www.passportjs.org

** mongoDB 와 mongoose 를 사용하고 있는 환경에서, 보다 쉽게 passport 를 이용한 사용자 인증이 가능하도록 만들어주는 플러그인인

passport-local-mongoose 를 사용한다. 이는 기본적인 설정을(패스워드 확인 등) 미리 다 구성해놓았기때문에

편리하다.

 

https://github.com/saintedlama/passport-local-mongoose

 

saintedlama/passport-local-mongoose

Passport-Local Mongoose is a Mongoose plugin that simplifies building username and password login with Passport - saintedlama/passport-local-mongoose

github.com


회원가입, 로그인 구현

 

준비사항

 

1. 로그인과 조인을 위한 템플릿

//main 템플릿
    
    Doctype <!DOCTYPE html>
	html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
    body
        include ../partials/header
        block content
    
    
//home 템플릿
    
	extends layout/main

	block content
	h1 로그인을 해보자
    
    
//join 템플릿
   
   form(action="/join", method="post")
            input(type="text", name="name", placeholder="Full Name", required=true)
            input(type="email", name="email", placeholder="Email", required=true)
            input(type="password", name="password", placeholder="Password", required=true)
            input(type="password", name="password2", placeholder="Verify password", required=true)
            input(type="submit", value="Join now")
            
            
//login 템플릿
   
           form(action="/login", method="post")
            input(type="email", name="email", placeholder="Email", required=true)
            input(type="password", name="password", placeholder="password", required=true)
            input(type="submit", value="Log in")

2. 몽고db, 몽구스가 설치되어있고, db.js 도 구성되어있어야함.

2020/02/29 - [Study/script.js] - [full]mongoDB, mongoose

 

[full]mongoDB, mongoose

mongoDB = NoSQL Databass mongoose = mongoDB와 자바스크립트를 연결 시켜줌 장점 - 적은 규칙과 절차가 간편하게 작업이 가능한 데이터 베이스 이다. 1. mongoDB 다운로드 https://www.mongodb.com/cloud/atlas/..

andwinter.tistory.com

3. 라우터와 컨트롤러의 준비

//라우터

globalRouter.get("/join", getJoin);
globalRouter.post("/join", postJoin, getLogin);

globalRouter.get("/login", getLogin);
globalRouter.post("/login", postLogin);

//컨트롤러

export const getJoin = (req, res) => {
  res.render("join");
};
export const postJoin = (req, res, next) => {};

export const getLogin = (req, res) => {
  res.render("login");
};
export const postLogin = (req, res) => {};

 당연한거니까..


회원가입(Join)

 

우선 User 모델을 만들어준다

 

이때 passportLocalMongoose 가 쓰이기 때문에 설치해준다.

npm i passport-local-mongoose

import mongoose from "mongoose";
import passportLocalMongoose from "passport-local-mongoose"
const UserSchema = new mongoose.Schema({
  name: String,
  email: String
});

UserSchema.plugin(passportLocalMongoose, { usernameField: "email" });

const model = mongoose.model("User", UserSchema);

export default model;

여기서 passportLocalMongoose의 usernameField 는 사용자의 이름이 어떤놈이 될지를 정하는 것이다.

이렇게 세팅해놓으면 알아서 passportLocalMongoose 가 패스워드 인증이라던지 회원 이름의 변경이라던지 잡다한 일들을 알아서 해줄것이다.

 

이후에 passport를 설치해준다.

 

npm i passport passport-local

passport 와 passport-local 둘다 설치해준다.

그리고 passport.js 를 상위 디렉토리에 생성한뒤 

import passport from "passport"
import User from "./model/User"

passport.use(User.createStrategy())

passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

위와같이 적는다.

여기서 createStrategy() 란 passportLocalMongoose 의 메소드로

passport-local 의 LocalStrategy 인스텐스를 만든다(원래는 조금더 귀찮고 복잡한 passport의 과정이지만 passportLocalMongoose 에의해 한줄로 구현가능하다.

 

serializeUser, deserializeUser 또한 마찬가지로 serialization 은 현재 브라우저의 유저에 대하여 어떠한 정보를 쿠키가 가질수 있는가 를 의미(보안상의 이유로 user.id 만을 넘겨주길 권장) 하며(쿠키에 어떤 필드만을 넘겨 저장시킬것인가) deserialization 은 쿠키의 정보를 통하여 어떻게 유저를 찾을것인가 를 의미한다.

원래는 직접 설정해 주어야 하지만 이역시 passportLocalMongoose 에 의하여 간단하게 위처럼 작성 가능하다.

 

이제 컨트롤러 부분(postJoin)을 수정한다.

import User from '../model/User';
import passport from 'passport';

export const postJoin = async (req, res, next) => {
  const {
    body: { name, email, password, password2 }
  } = req;
  //body-parser 에 의하여 request 에서 폼의 데이터를 가져올수 있다.
  
  if (password !== password2) { //입력한 두 패스워드가 일치하지 않다면
    res.render("join"); //다시 가입화면으로 돌려보낸다.
  } else { //만약 일치하다면
    try {
      const user = await User({ //model 에 등록된 User 스키마에 맞추어 객체 생성
        name,
        email
      });
      await User.register(user, password); //mongoDB에 등록
      next(); //다음으로 넘김(login 화면으로)
    } catch (error) {
      console.log(error);
      res.redirect("/"); //실패할 경우 홈으로 redirect
    }
  }
};

 

postJoin 즉 사용자가 가입 양식을 모두 채워 post 했을때

 

1. body-parser 에 의하여 폼의 데이터가 넘어온다

2. 사용자가 입력한 폼의 데이터중 password 가 일치한지 검사한다.

3. 일치하지 않다면 join 화면으로 돌려보내고 일치하다면

4. mongoose 의 model 안에 있는 User Schema 에 맞추어 object 를 생성한다.

4-1.여기서 Model() 과 Model.create() 의 차이는 객체만 만드는지 객체를 생성후 db에 저장까지 할 것인가의 차이이다. 여기서 create 를 한다면 register 전에 이미 db에 등록되어버려 이미 사용자가 등록되어있다는 오류가 뜨게 되기 때문에 Model() method 를 사용한다.

5. User.register를 이용해 db에 사용자를 등록한다.

6. 이후 next() 를 이용해 다음 컨트롤러가 작동하게 만든다.(postLogin)

6-1. 만약 error 가 있다면 에러메세지를 출력후 home 으로 이동한다.

 

이제 join 을 통해 회원가입을 진행하면

mongoDB에서 방금 가입한 회원을 확인 할 수 있다.


로그인(Login)

 

postJoin 에서 회원가입이 이루어진 뒤, next 를 통해 다음으로 넘기게 했었는데,

라우터에서 그 다음이 무엇인지를 설정해준다.

globalRouter.post("/join", postJoin, postLogin);

이 다음은 postLogin 이다. 

postJoin 은 next 를 가진 미들웨어로써 자신이 사용한 정보를 다음으로 넘겨줄 수있는데

그 정보를 postLogin 에서 받아서 사용자를 로그인 시키게 될 것이다.

 

우선 userController 에서 passport 를 import 해준뒤,

아래처럼 코드를 작성한다.

import passport from "passport";

//중략

export const postLogin = passport.authenticate("local", {
  failureRedirect: "/login",
  successRedirect: "/"
})

passport.authenticate() 기본적으로 userName 과 password 를 찾아보도록 설정되어있고,

passport-local 의 인증을 실행하고 이후 인증이 성공했을때의 redirect 와 실패했을때의 redirect 를 설정 할 수 있다.

나 같은경우는 인증이 성공했을때 홈으로, 실패했을때는 다시 로그인 화면으로 가게 구성했다.

그리고 app.js로 가서

import passport from "passport";
import "./passport";


//미들웨어 마지막에
app.use(passport.initialize());

이렇게 passport 를 임폴트 하고 미들웨어의 맨 마지막에 passport.initialize() 를 붙여준다.

initialize 는 passport 를 초기화시키고 구동시키는 역할을 한다. 이놈이 없다면 오류가 뜬다.

 

이후 회원가입을 시도해보자.

그럼 홈화면으로 이동될텐데, 이는 postLogin 에서 인증이 성공했을때 successRedirect를 이용해 홈으로 가게 했기 때문이다.

 


근데좀 뭔가 로그인이 된지 안된지 모르겠고 꺼림칙하니 템플릿과 미들웨어를 추가하여 로그인 되었는지를 확인해 보자.

 

우선 미들웨어를 작성한다.

 

middleware.js 파일을 만들고(귀찮다면 app.js에 직접 작성해도 된다.)

export const localMiddleware = (req, res, next) => {
  res.locals.user = req.user || null;
  console.log(req.user);
  next();
};

위처럼 작성한다.

기본적으로 passport 는 인증이 성공하면 req.user 에 인증성공한 사용자의 정보를 어느 라우터에서든 반환하게 된다.

때문에 console.log(req.user) 을 사용하면 현재 로그인한 사용자의 정보를 조회할 수 있다.

이제 템플릿에서 user 을 사용하여 홈화면에 출력되는 로그인을 해보자!! 를 로그인 되었다!! 로 바꾸도록 할것이다.

extends layout/main

block content
    if !user
        h1 로그인을 해보자
    else
        h1 로그인이 되었습니다!!!

if else 문을 사용하여 미들웨어에서 보내주는 user에 대한 정보가 있다면 로그인이 되었습니다! 를 출력하도록 바꿔준다.

 

이 후 가입했던 아이디와 비밀번호로 로그인을 해보자.

홈으로 redirect 되긴 하지만, 메세지가 바뀌질 않는다. 이는 req,user 가 존재하지 않는다는 뜻이다.

이는 세션에 사용자에 대한 정보가 담긴 쿠키가 없기 때문이다. 그렇기 때문에 passport.session 이라는 놈이 필요하고, 또 express-session 이라는 패키지가 필요하다.

 

npm i express-session

 

으로 패키지를 설치한 뒤, app.js 에서 아래와 같이 세팅해준다.

import session from "express-session";

//중략

app.use(
session({
      secret: "dwdasjfu123@#@fc",
      resave: true,
      saveUninitialized: false
    })
  );
app.use(passport.initialize());
app.use(passport.session());

//생략

express-session 의 secret 는 특정 문자열을 이용하여 사용자의 정보를 암호화한 후 쿠키에 저장하게된다.(필수 옵션)

 

그리고 passport.session() 은 로그인상태가 유지될 수 있게 만들어 준다.

 

이렇게까지 해주면 다른 라우터로 이동하여도 쿠키에 저장된 사용자의 정보를 passport가 매번

deserialize 하며 로그인 상태를 유지시킬 수 있게 한다.

 

이제 확인해 보면,

 

쿠키가 저장되고 메세지도 바뀌는걸 볼 수 있다. 즉 로그인 된 상태라는걸 알 수 있다.

또한 콘솔로그에서 

로그인한 사용자의 정보를 확인할 수 있다(req.user)


로그아웃(Log out)

 

로그아웃은 생각보다 간단하다.

req.logout() 을 이용하면 된다. 이는 passport 에서 권장하는 방법이란다.

하지만.. 쿠키가 지워지지 않는다. 또 어디서보니 세션이 완전히 지워지지 않는다는 얘기가 있기때문에

req.session.destroy 를 이용하여 세션도 파괴하고 남는 쿠키까지 지워보자.

 

export const logout = (req, res) => {
  req.logout(); //사용자 로그아웃
  req.session.destroy(() => { //세션 파괴
    res.clearCookie('connect.sid'); //쿠키 삭제
    res.redirect('/'); //홈으로 redirect
});
};

Session Store

 

이제 마지막으로 세션의 정보를 서버가 재실행되었을때도 사용자의 로그인정보가 그대로 남아있도록 만들어 보자.

 

일단 지금까지 한 상태로 로그인을하고 서버를 재실행 시켜보자.

로그인이 해제된다. 이는 세션이 날라가버리는것이다.

 

이를 해결하기 위하여 connect-mongo 를 이용할 것이다.

 

세션 스토어 라는 개념은 세션이 데이터를 저장하는 곳으로써 기본값은 memory store 이다.

memory store 는 기본적으로 휘발성으로서 서버가 재실행되면 세션이 날라가버린다.

 

이를 Mongo store 로 하여, DB에 세션 저장소를 만들고 아무리 서버가 재실행 되더라도

로그인정보가 유지되도록 만들어 본다.

 

필요한 것으로 connect-mongo 가 있다.

npm i  connect-mongo

로 설치해준다.

 

app.js 에서 설치한놈을 import 하고 mongoose 도 import 한다.

https://github.com/jdesboeufs/connect-mongo

 

jdesboeufs/connect-mongo

MongoDB session store for Express. Contribute to jdesboeufs/connect-mongo development by creating an account on GitHub.

github.com

connect-mongo 의 사용법에 따라서 한다.

 

import mongoose from "mongoose"
import MongoStore from "connect-mongo"

const Store = MongoStore(session)

app.use(
    session({
      secret: "dwdasjfu123@#@fc",
      resave: false,
      saveUninitialized: false,
      store:new Store({mongooseConnection:mongoose.connection})
    })
  );

session 부분에 store 까지 추가하고나면 이제 서버가 재실행되더라도 로그인상태가 유지된다.

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
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
글 보관함