passport-local 를 통한 로그인

성민개발로그·2022년 3월 4일
0
post-thumbnail

먼저 이 글을 보기전에 선행으로 passport.js 사용기(passport-local) 전략짜기여기서 기본적인 passport.js 구현 흐름과 redux, redux-saga 의 기본적인 선행지식이 필요합니다.

구현순서:

1. 로그인 폼에서 이메일과 비밀번호 정보를 서버로 전달

로그인폼 onSubmit 함수:

const onFinish = (values) => {
      const {email} = values;
      const checkEmail = emailReg.exec(email); 
      if(checkEmail === null){ 
        //이메일 형식 검사 (정규표현식으로 통한 검증)
        return alert('이메일 형식 잘못 입력했습니다!');
      }
        dispatch({
          type:LOG_IN_REQUEST, //redux-saga로 비동기 로그인 요청,
          data:values // {email, password}
        })
      };

redux-saga,axios를 통한 로그인 정보 서버로 전달.


function logInAPI(data){
    return axios.post('/user/local',data)
  // axios 를 통한 서버에게 로그인 요청하기.
}

function* logIn(action){
    try{
    const result = yield call(logInAPI,action.data); 
      //서버에서 반환받은 user 정보 를 result에 반환.
    yield put({
        type:LOG_IN_SUCCESS,
        data:result.data 
      // state 에 저장하기 위해 reducer로 전달해 준다.
    })

    }catch(err){
        yield put({ 
          // redux 액션으로 보내줌. put:dispatch라고 생각하면 편하다.
            type:LOG_IN_FAILURE,
            error:err.response.data,
        })
    }
}

function* watchLogIn(){//2.
    yield takeLatest(LOG_IN_REQUEST,logIn); 
  //take 한번만 실행되고 이벤트 삭제된다. 이벤트 리스너 느낌을 준다.
}

export default function* userSaga(){//1
    yield all([
        fork(watchLogIn),
    ])
}

2. 서버에서 받아서 passport-local전략으로 로그인 하기

userRouter

router.post('/local',isNotLoggedIn, (req,res,next)=>{
  
 passport.authenticate('local',(err,user,info)=>{
   // 로그인성공하면 실행될 콜벡함수.
    if(err){
        console.error(err);
        return next(err);
    }
    if(info){
        return res.status(401).send(info.reason);
    }
    return req.login(user, async(loginErr)=>{
        if(loginErr){
            console.error(loginErr);
            return next(loginErr);
        }
        const userWithoutPassword = await User.findOne({
            where:{ id:user.id},
            attributes:['id','nickname','email'],
            include:[{
                model: Effect,
                attributes:['id','title','html','css'],
                include:[{
                    model: User,
                    as: 'Likers'
                },{
                    model: User,
                    attributes: ['id','nickname']
                }]
            }]
        })
        return res.status(200).json(userWithoutPassword);
      //최종 프론트로 전달해줄 유저정보.
    })
 })(req,res,next);   
});

local(): 로컥전략짜기.

module.exports = () =>{
    passport.use(new LocalStrategy({
        usernameField: 'email',
        passwordField: 'password',
    }, async (email, password, done)=>{
        try{
            const user = await User.findOne({
                where:{
                    email
                }
            });
            if(!user){
                return done(null,false,
                            {reason:'존재하지 않는 이메일입니다.'});
            }
            const compare = await bcrypt
            .compare(password,user.password);
          
            if(compare){
                return done(null,user);
            }
            return done(null,false,
                        {reason:'비밀번호가 일치하지 않습니다.'});
        }catch(error){
            console.error(error);
            return done(error);
        }
    }))
};
  • passport.serializeUser:
    첫로그인일때 성공하면 사용자 정보 객체를 세션에 아이디로 저장.
    매개변수로 user를 받아 done 함수에 두번째 인자로 user.id를 넘긴다. 이렇게 id만 저장하면 세션 용량이 커지는 걸 막을 수 있기 때문.
  • passport.deserializeUser:
    매번 다른 호출이 진행이되면 deserializeUser가 실행이 된다.
    프론트엔드에서 cookie 값을 받아와서 해당 값으로(app.use(cookieParser()) 미들웨어 사용해서 cookie파싱해준다.)세션에 저장한 아이디를 통해서 사용자 정보 객체를 불러옴.
    passport.session() 미들웨어가 이 메서드를 호출
    serializeUser에 저장했던 id를 받아서 데이터베이스에서 사용자 정보를 조회 조회한 정보를 req.user에 저장
module.exports = () =>{
    passport.serializeUser((user,done)=>{
        done(null, user.id); //id 값을 쿠키로 저장한다
    });

    passport.deserializeUser(async(id, done)=>{
        try{
            const user = await User.findOne({
                where:{
                    id,
                },
            });
            done(null, user);
        }catch(error){
            console.error(error);
            done(error);
        }
    });
    local();
};

느낀점:

한번더 프로젝트를 이용해서 passport.js 를 통한 로그인 전략을 짜 보니 로그인 흐름을 더 구체적으로 이해한거 같다 아직은 cookie와session 을 완벽하게 이해를 못해서 추가로 공부할 계획이다.

0개의 댓글