소셜 로그인을 구현하기 위해 몇가지를 공부했다. 먼저 로그인 정보를 유지하기 위해서는 세션의 도입이 필수 불가결한데, nodejs express에서 어떻게 세션을 다루는지, 또한 passportjs를 이용하여 어떻게 하면 구글 로그인을 구현할 수 있을지에 대해 알아보았다.
일단 sidebar에 임시로 구글로 로그인 링크를 걸어놓는다.
npm install -s passport passport-google-oauth
해당 명령어를 사용하여 passportjs로 google로그인을 하기 위한 준비를 한다.
유저 정보를 담을 user테이블의 Column으로는 구글로 로그인 했을 시 넘어오는 id값을 저장할 USER_CODE와 NICKNAME,그리고 해당 유저의 등급(ADMIN,USER)를 저장할 GROUP을 지정한다. 여기서 nickname을 Unique 값으로 지정해서 같은 닉네임으로 insert하려고 하면 오류를 발생시키도록 한다.
var findUser = function(id,callback){
db.query('SELECT * FROM USER WHERE USER_CODE=?',[id],(err,result)=>{
if(err){
callback(1);
console.log(err);
return;
} else{
if (result.length == 1){
callback(result[0])
} else if (result.length == 0){
callback(0);
}
}
});
}
var newUser = function(id,nickname,callback){
db.query('INSERT INTO USER (`USER_CODE`, `NICKNAME`, `GROUP`) VALUES (?,?,?)',[id,nickname,'USER'],(err)=>{
if(err){
if (err.errno == 1062)
callback(1);
else
callback(0);
} else{
callback(-1);
}
})
}
해당 유저가 존재하는지 확인하는 findUser함수, 새로운 유저를 등록하는 newUser함수를 db-query.js에 정의한다.
newUser에 있는 err.errno == 1062는 닉네임이 같은 유저가 있을 때 발생하는 오류코드이다.
var express = require('express');
var router = express.Router();
var db = require('../db-query');
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
router.use(passport.initialize());
router.use(passport.session());
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
var goolgeCred = require('../googleCred.json');
passport.use(new GoogleStrategy({
clientID: goolgeCred.web.client_id,
clientSecret: goolgeCred.web.client_secret,
callbackURL: goolgeCred.web.redirect_uris[0]
},
function(accessToken, refreshToken, profile, done) {
process.nextTick(function(){
var user = {}
db.findUser(profile.id,(response)=>{
user.id = profile.id;
console.log(profile.id);
if (response == 1){
return done(false);
} else if (response == 0){
user.newUser = true;
} else{
user.newUser = false;
user.nickname = response.NICKNAME;
user.group = response.GROUP;
}
return done(null,user);
});
})
}
));
router.get('/google',
passport.authenticate('google',
{ scope: ['https://www.googleapis.com/auth/plus.login'] }));
router.get('/google/callback',
passport.authenticate('google', { failureRedirect: '/login/google' }),
function(req, res) {
if(!req.session.passport.user.newUser){
res.redirect('/');
} else{
res.redirect('/login/register');
}
}
);
router.get('/register',function(req,res,next){
if(!req.session.passport.user.newUser){
res.render('error');
} else{
res.render('register');
}
});
router.post('/registerConfirm',function(req,res,next){
db.findUser(req.session.passport.user.id,(response)=>{
if (response != 0){
res.render('error');
} else{
db.newUser(req.session.passport.user.id,req.body.nickname,(response)=>{
res.send({result:response});
});
}
});
});
router.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
module.exports = router;
로그인과 회원가입의 라우팅을 담당할 login.js이다. 구글로부터 받은 API ID와 Secret은 따로 json파일로 분리하여 gitignore에 추가해줬다. findUser의 반환 값에 따라 분기한다, response가 1 이라면 오류가 발생한 것이고, 0이라면 새로운 유저임을, 그 외 라면 로그인에 성공하여 유저의 정보가 넘어온 것이다. 이때는 유저의 정보를 세션에 저장한다.
/register는 새로운 유저가 가입할 때 보여지는 페이지이다. session의 newUser가 true인지 확인해서 잘못된 접근을 막는다.
function register(){
var nickname = $('#nickname').val();
var pattern_kor = /[ㄱ-ㅎ|ㅏ-ㅣ]/; // 자모음체크
var pattern_spc = /[~!@#$%^&*()_+|<>?:{}]/; // 특수기호
var pattern_w = /\s/; // 공백
if( (pattern_w.test(nickname)) || (pattern_kor.test(nickname)) || (pattern_spc.test(nickname))){
alert('특수기호, 공백, 한글 자모음은 입력할 수 없습니다!');
return;
}
if (nickname.length < 2 || nickname.length > 10){
alert('2자 이상 10자 이하로 입력해주세요!');
return;
}
$.ajax({
url: '/login/registerConfirm',
datatype: 'json',
type: 'POST',
data:{
nickname: nickname
},
success: function(result){
result = result.result;
if(result == -1){
alert('완료되었습니다! 다시 로그인해주세요.');
location.href='/login/logout';
} else if (result == 1){
alert('이미 존재하는 닉네임입니다.');
$('#nickname').val('');
} else if (result == 0){
alert('알 수 없는 오류가 발생했습니다. 나중에 다시 시도하세요.');
}
}
})
}
닉네임 등록하기의 '완료' 버튼을 눌렀을 때 실행되는 register함수이다. 입려값에 공백이 들어갔거나 특수기호, 혹은 한글 자모음만 들어갔다면 생성을 막는다. 또한 2~10자를 벗어났을 때에도 생성을 막는다.
조건을 만족한다면 registerConfirm에 post요청을 보내서 해당 닉네임이 중복인지의 여부를 판단하고, 이에 따라 분기한다. 중복이 아니어서 성공적으로 계정정보를 등록했다면 다시 로그인해달라는 메시지와 함께 로그아웃하고(세션 정보를 한번 초기화하고) 메인 페이지로 넘긴다.
사이드바에서는 user값의 유무에 따라 로그인 버튼을 띄울 것인지 회원 정보를 띄울 것인지를 분기한다.
'Projects > NodeBoard' 카테고리의 다른 글
Summernote 에디터 적용, imgbb 서버로 게시글 이미지 업로드 (2) | 2021.04.29 |
---|---|
로그인 유저 글쓰기/댓글쓰기 차별화 (0) | 2021.04.05 |
댓글 답글 기능 구현 (0) | 2021.03.09 |
AJAX로 댓글달기 기능 구현 (5) | 2021.03.06 |
추천하기 기능 구현 (0) | 2021.03.03 |
댓글