박권수

feat. social Login & social Register

......@@ -12,6 +12,7 @@
"@google-cloud/storage": "^5.14.2",
"@koa/cors": "^3.1.0",
"firebase-admin": "^9.11.1",
"google-auth-library": "^7.10.0",
"koa-body": "^4.2.0",
"moment": "^2.29.1",
"moment-timezone": "^0.5.33",
......@@ -1741,9 +1742,9 @@
}
},
"node_modules/google-auth-library": {
"version": "7.9.2",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.9.2.tgz",
"integrity": "sha512-HjxbJt660a+YUTYAgYor87JCuBZvjUSNBExk4bXTEaMuCn8IHSDeHmFxKqThuDPrLCiKJp8blk/Ze8f7SI4N6g==",
"version": "7.10.0",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.0.tgz",
"integrity": "sha512-ICsqaU+lxMHVlDUzMrfVIEqnARw2AwBiZ/2KnNM6BcTf9Nott+Af87DTIzmlnW865p3REUP2MVL0xkPC3a61aQ==",
"dependencies": {
"arrify": "^2.0.0",
"base64-js": "^1.3.0",
......@@ -5182,9 +5183,9 @@
}
},
"google-auth-library": {
"version": "7.9.2",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.9.2.tgz",
"integrity": "sha512-HjxbJt660a+YUTYAgYor87JCuBZvjUSNBExk4bXTEaMuCn8IHSDeHmFxKqThuDPrLCiKJp8blk/Ze8f7SI4N6g==",
"version": "7.10.0",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.0.tgz",
"integrity": "sha512-ICsqaU+lxMHVlDUzMrfVIEqnARw2AwBiZ/2KnNM6BcTf9Nott+Af87DTIzmlnW865p3REUP2MVL0xkPC3a61aQ==",
"requires": {
"arrify": "^2.0.0",
"base64-js": "^1.3.0",
......
......@@ -20,6 +20,7 @@
"@google-cloud/storage": "^5.14.2",
"@koa/cors": "^3.1.0",
"firebase-admin": "^9.11.1",
"google-auth-library": "^7.10.0",
"koa-body": "^4.2.0",
"moment": "^2.29.1",
"moment-timezone": "^0.5.33",
......
......@@ -93,6 +93,7 @@ exports.searchHospital = async ctx => {
};
};
//의사 회원가입
exports.doctorRegister = async ctx => {
const {
userId,
......@@ -193,6 +194,7 @@ exports.doctorRegister = async ctx => {
}
//로컬 로그인
exports.login = async(ctx) => {
const { userId, password, deviceToken } = ctx.request.body;
......@@ -211,7 +213,7 @@ exports.login = async(ctx) => {
}
const user = await User.findByUserId(userId);
if(!user || !user.userTypeCd) {
if(!user || !user.userTypeCd || user.authTypeCd !== 'NORMAL') {
ctx.status = 401;
ctx.body = {
error : '존재하지 않는 회원입니다.',
......@@ -259,6 +261,180 @@ exports.login = async(ctx) => {
};
//social Register
exports.socialRegister = async ctx => {
const { socialType } = ctx.params;
const { accessToken, deviceToken } = ctx.request.body;
const verifyingToken =
socialType.toUpperCase() === 'GOOGLE' ? async () => {
//id_token
const result = jwt.decode(accessToken);
return {
userId : result.email,
userNm : result.name,
contact : null,
birth : null,
};
}
: socialType.toUpperCase() === 'NAVER' ? async () => {
const url = 'https://openapi.naver.com/v1/nid/me';
const result = await axios.get(url, {
headers : {
Authorization : `Bearer ${accessToken}`,
},
});
const { email, mobile, name, birthday, birthyear } = result.data.response;
return {
userId : email,
userNm : name,
contact : mobile,
birth : `${birthyear}-${birthday}`,
};
}
: socialType.toUpperCase() === 'KAKAO' ? async () => {
const url = 'https://kapi.kakao.com/v2/user/me';
const result = await axios.get(url, {
headers : {
Authorization : `Bearer ${accessToken}`,
},
});
console.log(result);
return result;
} : () => null;
const verifyingInfo = await verifyingToken();
if(!verifyingInfo || !verifyingInfo.userId) {
ctx.status = 403;
ctx.body = {
error : '잘못된 요청',
};
return;
}
const { userId, userNm, birth, contact } = verifyingInfo;
const existUser = await User.findByUserId(userId);
if(existUser) {
ctx.status = 409;
ctx.body = {
error : '이미 가입된 회원',
};
return;
}
const user = new User({
userId,
hashedPassword : null,
authTypeCd : socialType.toUpperCase(),
useYn : 'Y',
});
const profile = new Profile({
userId,
userNm,
birth,
contact,
deviceToken,
});
await user.save();
await profile.save();
ctx.status = 201;
};
//social Login
exports.socialLogin = async ctx => {
const { socialType } = ctx.params;
const { accessToken, deviceToken, } = ctx.request.body;
const verifyingToken =
socialType.toUpperCase() === 'GOOGLE' ? async () => {
//id_token : google Login
const result = jwt.decode(accessToken);
return result.email;
}
: socialType.toUpperCase() === 'NAVER' ? async () => {
//naver Login
const url = 'https://openapi.naver.com/v1/nid/me';
const result = await axios.get(url, {
headers : {
Authorization : `Bearer ${accessToken}`,
},
});
return result.data.response.email;
}
: socialType.toUpperCase() === 'KAKAO' ? async () => {
//kakao Login
const url = 'https://kapi.kakao.com/v2/user/me';
const result = await axios.get(url, {
headers : {
Authorization : `Bearer ${accessToken}`,
},
});
console.log(result);
return result;
} : () => null;
const userId = await verifyingToken();
if(!userId) {
ctx.status = 403;
ctx.body = {
error : '잘못된 요청입니다',
};
return;
}
const user = await User.findByUserId(userId);
if(!user || user.useYn !== 'Y') {
ctx.status = 404;
ctx.body = {
error : '존재하지 않는 회원입니다.',
};
return;
} else if (user.authTypeCd !== socialType.toUpperCase()) {
ctx.status = 400;
ctx.body = {
error : '잘못된 소셜 로그인입니다.',
};
return;
}
const profile = await Profile.findOne({ userId });
if(profile.deviceToken !== deviceToken) {
profile.updateDeviceToken(deviceToken);
await profile.save();
}
const token = await user.generateToken();
ctx.status = 200;
ctx.body = {
userTypeCd : user.userTypeCd,
token,
};
};
exports.logout = async(ctx) => {
ctx.cookies.set('access_token', null, {
httpOnly : true,
......
......@@ -5,7 +5,7 @@ const authCtrl = require('./auth.ctrl')
const auth = new Router()
/**
* 회원가입 (email type) : 환자 회원가입
* 로컬 회원가입 (email type) : 환자 회원가입
* url : http://localhost:4000/api/auth/register
* request parameter : userId, password, passwordCheck
* return : null
......@@ -21,7 +21,7 @@ auth.post('/register', authCtrl.register)
auth.get('/hospital', authCtrl.searchHospital);
/**
* 회원가입 (email type) : 의사 회원가입
* 로컬 회원가입 (email type) : 의사 회원가입
* url : http://localhost:4000/api/auth/register/doctor
* request parameter : userId, password, passwordCheck, doctorInfo(File)
* return : null
......@@ -29,14 +29,30 @@ auth.get('/hospital', authCtrl.searchHospital);
auth.post('/register/doctor', KoaBody, authCtrl.doctorRegister)
/**
* 로그인 (email type)
* 로컬 로그인 (email type)
* url : http://localhost:4000/api/auth/login
* request parameter : userId, password
* return : userId
* return : token, userTypeCd
*/
auth.post('/login', authCtrl.login)
/**
* 소셜 회원가입(Google, Naver, Kakao)
* url : http://localhost:4000/api/auth/register/${socialType}
* request parameter : accessToken
* return : status
*/
auth.post('/register/social/:socialType', authCtrl.socialRegister);
/**
* 소셜 로그인(Google, Naver, Kakao)
* url : http://localhost:4000/api/auth/login/${socialType}
* request parameter
* return : token, userTypeCd
*/
auth.post('/login/social/:socialType', authCtrl.socialLogin);
/**
* 로그아웃
* url : http://localhost:4000/api/auth/logout
* request parameter : null
......
......@@ -5,9 +5,10 @@ const jwt = require('jsonwebtoken');
const Schema = mongoose.Schema;
const UserSchema = new Schema ({
userId : { type: String, required : true, unique : true, lowercase : true, },
hashedPassword : { type : String, required : true },
userTypeCd : { type : String, required : true, default : 'NORMAL' },
userId : { type: String, required : true, unique : true, lowercase : true, trim : true },
hashedPassword : { type : String, required : true, },
userTypeCd : { type : String, required : true, default : 'NORMAL', uppercase : true, },
authTypeCd : { type : String, required : true, default : 'NORMAL', uppercase : true, },
useYn : { type : String, default : 'W', required : true, },
});
......
......@@ -1134,10 +1134,10 @@
dependencies:
"type-fest" "^0.20.2"
"google-auth-library@^7.0.0", "google-auth-library@^7.0.2", "google-auth-library@^7.6.1":
"integrity" "sha512-HjxbJt660a+YUTYAgYor87JCuBZvjUSNBExk4bXTEaMuCn8IHSDeHmFxKqThuDPrLCiKJp8blk/Ze8f7SI4N6g=="
"resolved" "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.9.2.tgz"
"version" "7.9.2"
"google-auth-library@^7.0.0", "google-auth-library@^7.0.2", "google-auth-library@^7.10.0", "google-auth-library@^7.6.1":
"integrity" "sha512-ICsqaU+lxMHVlDUzMrfVIEqnARw2AwBiZ/2KnNM6BcTf9Nott+Af87DTIzmlnW865p3REUP2MVL0xkPC3a61aQ=="
"resolved" "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.0.tgz"
"version" "7.10.0"
dependencies:
"arrify" "^2.0.0"
"base64-js" "^1.3.0"
......