JS/Node.js

[NodeJS] MongoDB를 이용한 로그인 구현 및 토큰 생성

kth990303 2021. 6. 21. 16:33
반응형

이번엔 로그인 기능을 구현하고, 로그인에 성공하면 토큰을 생성하도록 코드를 짜보는 연습을 해보았다.

강의를 들으면서 타이핑했는데 콜백함수와 자바스크립트에 대한 이해도를 높일 뿐 아니라, 로그인 구현을 하는 방법에 대해 어렴풋이 알게 된 좋은 기회였다.

자바스크립트를 오랜만에 해서 기억이 드문드문 나는 상태였는데, 역시 하면서 감을 살리는 것이 베스트인 듯하다.

bcrypt로 암호화한 패스워드와 일치여부를 확인해 쿠키에 토큰을 저장하였다.

전체코드는 여기서 볼 수 있다.

https://github.com/kth990303/boiler-plate-prac

 

kth990303/boiler-plate-prac

Practice Boiler-Plate use NodeJS, React. Contribute to kth990303/boiler-plate-prac development by creating an account on GitHub.

github.com


로그인 API 생성하기

register 라우트 메소드도 만들었으니 이제 login 라우트 메소드를 만들 차례이다.

아래와 같이 코드를 작성해주자.

app.post('/login', (req, res)=>{
    // 요청된 이메일을 db에서 찾는다.
    
    // 요청된 이메일이 db에 있다면 비밀번호 일치여부 확인
    
    // 일치 시, 토큰 생성. 생성한 토큰을 쿠키에 저장한다
});

유저가 이메일과 비밀번호를 서버에 보내주면

서버가 이메일과 비밀번호 일치 여부를 확인한 후 토큰을 유저에게 생성해주는 기능을 작성해보도록 하겠다.


이메일 여부 확인

app.post('/login', (req, res)=>{
    // 요청된 이메일을 db에서 찾는다.
    User.findOne({email: req.body.email}, (err, user)=>{
        if(!user){
            return res.json({
                loginSuccess: false,
                message: "Unvalid email"
            });
        }
        // 요청된 이메일이 db에 있다면 비밀번호 일치여부 확인
        // 일치 시, 토큰 생성
    });  
});

몽구스의 findOne 메소드로 이메일 존재 여부를 확인할 수 있다.

mysql이라면 sequelize ORM으로 findone을 해주면 될듯하다.

 

만약 유저가 존재하지 않는다면 위 json 데이터를 보내준다.


비밀번호 일치여부 확인

db에 저장된 유저와 비교해야되므로 User.js의 userSchema의 메소드를 만들어줄 것이다.

userSchema.methods.comparePassword=function(plainPassword, cb){
    bcrypt.compare(plainPassword, this.password, function(err, isMatch){
        if(err) return cb(err);
        cb(null, isMatch);
    });
}

bcrypt의 compare 메소드로 비밀번호 일치여부를 확인할 수 있다.

단, bcrypt로 암호화된 암호를 복호화하는 것은 불가능하므로 (만약 가능했다면 암호화한 의미가 없는 것이니...)

plainPassword를 암호화한 것이 암호화된 암호랑 일치하는지 확인해주는 방법을 이용해주어야 한다.

 

userSchema의 comparePassword() 메소드를 생성해주고,

index.js에서 사용되는 메소드이므로 콜백함수를 인자로 담아주어야 한다.

 

콜백함수의 첫번째 인자는 err를 담아주어야 하는데, err가 딱히 없으므로 cb(null, isMatch(일치함)) 을 보내주면 된다.

app.post('/login', (req, res)=>{
    // 요청된 이메일을 db에서 찾는다.
    User.findOne({email: req.body.email}, (err, user)=>{
        if(!user){
            return res.json({
                loginSuccess: false,
                message: "Unvalid email"
            });
        }
        // 요청된 이메일이 db에 있다면 비밀번호 일치여부 확인
        user.comparePassword(req.body.password, (err, isMatch)=>{
            if(!isMatch)
                return res.json({
                    loginSuccess:false,
                    message:"Wrong password"
                });
            // 일치 시, 토큰 생성 후 쿠키에 저장
        });
    });
});

index.js 코드는 위와 같이 작성될 것이다.

User.js의 comparePassword(plainPassword, (callback function)) 에 plainPassword를 보내주기 위해 req.body.password를 인자에 담아준다. req.body.password는 클라이언트가 요청으로 보낸 비밀번호를 의미한다.


토큰 생성 후 쿠키에 저장

토큰을 사용하기 위해 jsonwebtoken 라이브러리를 install 해준다.

npm install jsonwebtoken --save
const jwt=require('jsonwebtoken');

역시 userSchema의 메소드를 따로 만들어준다.

userSchema.methods.generateToken=function(cb){
    const user=this;
    const token=jwt.sign(user._id.toHexString(), 'secretToken');
    user.token=token;
    user.save(function(err, user){
        if(err) return cb(err);
        cb(null, user);
    });
}

유저의 토큰을 만들어주는 것이므로 models.user 자체를 담아야 하므로 userSchema의 this를 담아주었다.

(자바스크립트에서 this랑 콜백함수의 중요성을 차차 깨닫고 있다. 다시 자바스크립트 기본서를 읽어야 할 필요성을 느끼는 중...)

user.save는 몽구스 자체 메소드, jwt.sign은 토큰 생성 관련 자체 메소드이다. 

나중에 좀 더 공부를 해봐야겠다.

app.post('/login', (req, res)=>{
    // 요청된 이메일을 db에서 찾는다.
    User.findOne({email: req.body.email}, (err, user)=>{
        if(!user){
            return res.json({
                loginSuccess: false,
                message: "Unvalid email"
            });
        }
        // 요청된 이메일이 db에 있다면 비밀번호 일치여부 확인
        user.comparePassword(req.body.password, (err, isMatch)=>{
            if(!isMatch)
                return res.json({
                    loginSuccess:false,
                    message:"Wrong password"
                });
            // 일치 시, 토큰 생성
            user.generateToken((err, user)=>{
                if(err) return res.status(400).send(err);
                // 토큰을 쿠키에 저장
                res.cookie("x_auth", user.token)
                .status(200)
                .json({
                    loginSuccess: true,
                    userId: user._id
                });
            });
            
        });
    });
});

쿠키명은 로그인 인증 쿠키이므로 x_auth로 설정해준 모습을 볼 수 있다.

user._id 는 아래 사진의 주황색 부분인 _id를 의미한다.

토큰 생성코드 작성 후 로그인을 시도하면 토큰이 생성됨.


나중에 개인 프로젝트로 mysql + sequelize + nodejs로 로그인 구현을 스스로 만들어보는 연습도 해봐야겠다.

 

반응형