Showing
6 changed files
with
213 additions
and
18 deletions
... | @@ -12,6 +12,7 @@ | ... | @@ -12,6 +12,7 @@ |
12 | "@google-cloud/storage": "^5.14.2", | 12 | "@google-cloud/storage": "^5.14.2", |
13 | "@koa/cors": "^3.1.0", | 13 | "@koa/cors": "^3.1.0", |
14 | "firebase-admin": "^9.11.1", | 14 | "firebase-admin": "^9.11.1", |
15 | + "google-auth-library": "^7.10.0", | ||
15 | "koa-body": "^4.2.0", | 16 | "koa-body": "^4.2.0", |
16 | "moment": "^2.29.1", | 17 | "moment": "^2.29.1", |
17 | "moment-timezone": "^0.5.33", | 18 | "moment-timezone": "^0.5.33", |
... | @@ -1741,9 +1742,9 @@ | ... | @@ -1741,9 +1742,9 @@ |
1741 | } | 1742 | } |
1742 | }, | 1743 | }, |
1743 | "node_modules/google-auth-library": { | 1744 | "node_modules/google-auth-library": { |
1744 | - "version": "7.9.2", | 1745 | + "version": "7.10.0", |
1745 | - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.9.2.tgz", | 1746 | + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.0.tgz", |
1746 | - "integrity": "sha512-HjxbJt660a+YUTYAgYor87JCuBZvjUSNBExk4bXTEaMuCn8IHSDeHmFxKqThuDPrLCiKJp8blk/Ze8f7SI4N6g==", | 1747 | + "integrity": "sha512-ICsqaU+lxMHVlDUzMrfVIEqnARw2AwBiZ/2KnNM6BcTf9Nott+Af87DTIzmlnW865p3REUP2MVL0xkPC3a61aQ==", |
1747 | "dependencies": { | 1748 | "dependencies": { |
1748 | "arrify": "^2.0.0", | 1749 | "arrify": "^2.0.0", |
1749 | "base64-js": "^1.3.0", | 1750 | "base64-js": "^1.3.0", |
... | @@ -5182,9 +5183,9 @@ | ... | @@ -5182,9 +5183,9 @@ |
5182 | } | 5183 | } |
5183 | }, | 5184 | }, |
5184 | "google-auth-library": { | 5185 | "google-auth-library": { |
5185 | - "version": "7.9.2", | 5186 | + "version": "7.10.0", |
5186 | - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.9.2.tgz", | 5187 | + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.0.tgz", |
5187 | - "integrity": "sha512-HjxbJt660a+YUTYAgYor87JCuBZvjUSNBExk4bXTEaMuCn8IHSDeHmFxKqThuDPrLCiKJp8blk/Ze8f7SI4N6g==", | 5188 | + "integrity": "sha512-ICsqaU+lxMHVlDUzMrfVIEqnARw2AwBiZ/2KnNM6BcTf9Nott+Af87DTIzmlnW865p3REUP2MVL0xkPC3a61aQ==", |
5188 | "requires": { | 5189 | "requires": { |
5189 | "arrify": "^2.0.0", | 5190 | "arrify": "^2.0.0", |
5190 | "base64-js": "^1.3.0", | 5191 | "base64-js": "^1.3.0", | ... | ... |
... | @@ -20,6 +20,7 @@ | ... | @@ -20,6 +20,7 @@ |
20 | "@google-cloud/storage": "^5.14.2", | 20 | "@google-cloud/storage": "^5.14.2", |
21 | "@koa/cors": "^3.1.0", | 21 | "@koa/cors": "^3.1.0", |
22 | "firebase-admin": "^9.11.1", | 22 | "firebase-admin": "^9.11.1", |
23 | + "google-auth-library": "^7.10.0", | ||
23 | "koa-body": "^4.2.0", | 24 | "koa-body": "^4.2.0", |
24 | "moment": "^2.29.1", | 25 | "moment": "^2.29.1", |
25 | "moment-timezone": "^0.5.33", | 26 | "moment-timezone": "^0.5.33", | ... | ... |
... | @@ -93,6 +93,7 @@ exports.searchHospital = async ctx => { | ... | @@ -93,6 +93,7 @@ exports.searchHospital = async ctx => { |
93 | }; | 93 | }; |
94 | }; | 94 | }; |
95 | 95 | ||
96 | +//의사 회원가입 | ||
96 | exports.doctorRegister = async ctx => { | 97 | exports.doctorRegister = async ctx => { |
97 | const { | 98 | const { |
98 | userId, | 99 | userId, |
... | @@ -193,6 +194,7 @@ exports.doctorRegister = async ctx => { | ... | @@ -193,6 +194,7 @@ exports.doctorRegister = async ctx => { |
193 | 194 | ||
194 | } | 195 | } |
195 | 196 | ||
197 | +//로컬 로그인 | ||
196 | exports.login = async(ctx) => { | 198 | exports.login = async(ctx) => { |
197 | const { userId, password, deviceToken } = ctx.request.body; | 199 | const { userId, password, deviceToken } = ctx.request.body; |
198 | 200 | ||
... | @@ -211,7 +213,7 @@ exports.login = async(ctx) => { | ... | @@ -211,7 +213,7 @@ exports.login = async(ctx) => { |
211 | } | 213 | } |
212 | 214 | ||
213 | const user = await User.findByUserId(userId); | 215 | const user = await User.findByUserId(userId); |
214 | - if(!user || !user.userTypeCd) { | 216 | + if(!user || !user.userTypeCd || user.authTypeCd !== 'NORMAL') { |
215 | ctx.status = 401; | 217 | ctx.status = 401; |
216 | ctx.body = { | 218 | ctx.body = { |
217 | error : '존재하지 않는 회원입니다.', | 219 | error : '존재하지 않는 회원입니다.', |
... | @@ -259,6 +261,180 @@ exports.login = async(ctx) => { | ... | @@ -259,6 +261,180 @@ exports.login = async(ctx) => { |
259 | 261 | ||
260 | }; | 262 | }; |
261 | 263 | ||
264 | +//social Register | ||
265 | +exports.socialRegister = async ctx => { | ||
266 | + const { socialType } = ctx.params; | ||
267 | + const { accessToken, deviceToken } = ctx.request.body; | ||
268 | + | ||
269 | + const verifyingToken = | ||
270 | + socialType.toUpperCase() === 'GOOGLE' ? async () => { | ||
271 | + //id_token | ||
272 | + const result = jwt.decode(accessToken); | ||
273 | + | ||
274 | + return { | ||
275 | + userId : result.email, | ||
276 | + userNm : result.name, | ||
277 | + contact : null, | ||
278 | + birth : null, | ||
279 | + }; | ||
280 | + } | ||
281 | + : socialType.toUpperCase() === 'NAVER' ? async () => { | ||
282 | + const url = 'https://openapi.naver.com/v1/nid/me'; | ||
283 | + const result = await axios.get(url, { | ||
284 | + headers : { | ||
285 | + Authorization : `Bearer ${accessToken}`, | ||
286 | + }, | ||
287 | + }); | ||
288 | + | ||
289 | + const { email, mobile, name, birthday, birthyear } = result.data.response; | ||
290 | + | ||
291 | + return { | ||
292 | + userId : email, | ||
293 | + userNm : name, | ||
294 | + contact : mobile, | ||
295 | + birth : `${birthyear}-${birthday}`, | ||
296 | + }; | ||
297 | + } | ||
298 | + : socialType.toUpperCase() === 'KAKAO' ? async () => { | ||
299 | + const url = 'https://kapi.kakao.com/v2/user/me'; | ||
300 | + const result = await axios.get(url, { | ||
301 | + headers : { | ||
302 | + Authorization : `Bearer ${accessToken}`, | ||
303 | + }, | ||
304 | + }); | ||
305 | + | ||
306 | + console.log(result); | ||
307 | + | ||
308 | + return result; | ||
309 | + } : () => null; | ||
310 | + | ||
311 | + | ||
312 | + const verifyingInfo = await verifyingToken(); | ||
313 | + if(!verifyingInfo || !verifyingInfo.userId) { | ||
314 | + ctx.status = 403; | ||
315 | + ctx.body = { | ||
316 | + error : '잘못된 요청', | ||
317 | + }; | ||
318 | + | ||
319 | + return; | ||
320 | + } | ||
321 | + | ||
322 | + const { userId, userNm, birth, contact } = verifyingInfo; | ||
323 | + | ||
324 | + const existUser = await User.findByUserId(userId); | ||
325 | + if(existUser) { | ||
326 | + ctx.status = 409; | ||
327 | + ctx.body = { | ||
328 | + error : '이미 가입된 회원', | ||
329 | + }; | ||
330 | + | ||
331 | + return; | ||
332 | + } | ||
333 | + | ||
334 | + const user = new User({ | ||
335 | + userId, | ||
336 | + hashedPassword : null, | ||
337 | + authTypeCd : socialType.toUpperCase(), | ||
338 | + useYn : 'Y', | ||
339 | + }); | ||
340 | + | ||
341 | + const profile = new Profile({ | ||
342 | + userId, | ||
343 | + userNm, | ||
344 | + birth, | ||
345 | + contact, | ||
346 | + deviceToken, | ||
347 | + }); | ||
348 | + | ||
349 | + await user.save(); | ||
350 | + await profile.save(); | ||
351 | + | ||
352 | + ctx.status = 201; | ||
353 | + | ||
354 | +}; | ||
355 | + | ||
356 | +//social Login | ||
357 | +exports.socialLogin = async ctx => { | ||
358 | + const { socialType } = ctx.params; | ||
359 | + const { accessToken, deviceToken, } = ctx.request.body; | ||
360 | + | ||
361 | + const verifyingToken = | ||
362 | + socialType.toUpperCase() === 'GOOGLE' ? async () => { | ||
363 | + //id_token : google Login | ||
364 | + const result = jwt.decode(accessToken); | ||
365 | + | ||
366 | + return result.email; | ||
367 | + } | ||
368 | + : socialType.toUpperCase() === 'NAVER' ? async () => { | ||
369 | + //naver Login | ||
370 | + const url = 'https://openapi.naver.com/v1/nid/me'; | ||
371 | + const result = await axios.get(url, { | ||
372 | + headers : { | ||
373 | + Authorization : `Bearer ${accessToken}`, | ||
374 | + }, | ||
375 | + }); | ||
376 | + | ||
377 | + return result.data.response.email; | ||
378 | + } | ||
379 | + : socialType.toUpperCase() === 'KAKAO' ? async () => { | ||
380 | + //kakao Login | ||
381 | + const url = 'https://kapi.kakao.com/v2/user/me'; | ||
382 | + const result = await axios.get(url, { | ||
383 | + headers : { | ||
384 | + Authorization : `Bearer ${accessToken}`, | ||
385 | + }, | ||
386 | + }); | ||
387 | + | ||
388 | + console.log(result); | ||
389 | + | ||
390 | + return result; | ||
391 | + } : () => null; | ||
392 | + | ||
393 | + | ||
394 | + const userId = await verifyingToken(); | ||
395 | + if(!userId) { | ||
396 | + ctx.status = 403; | ||
397 | + ctx.body = { | ||
398 | + error : '잘못된 요청입니다', | ||
399 | + }; | ||
400 | + | ||
401 | + return; | ||
402 | + } | ||
403 | + | ||
404 | + const user = await User.findByUserId(userId); | ||
405 | + if(!user || user.useYn !== 'Y') { | ||
406 | + ctx.status = 404; | ||
407 | + ctx.body = { | ||
408 | + error : '존재하지 않는 회원입니다.', | ||
409 | + }; | ||
410 | + | ||
411 | + return; | ||
412 | + } else if (user.authTypeCd !== socialType.toUpperCase()) { | ||
413 | + ctx.status = 400; | ||
414 | + ctx.body = { | ||
415 | + error : '잘못된 소셜 로그인입니다.', | ||
416 | + }; | ||
417 | + | ||
418 | + return; | ||
419 | + } | ||
420 | + | ||
421 | + const profile = await Profile.findOne({ userId }); | ||
422 | + if(profile.deviceToken !== deviceToken) { | ||
423 | + profile.updateDeviceToken(deviceToken); | ||
424 | + await profile.save(); | ||
425 | + } | ||
426 | + | ||
427 | + | ||
428 | + const token = await user.generateToken(); | ||
429 | + | ||
430 | + ctx.status = 200; | ||
431 | + ctx.body = { | ||
432 | + userTypeCd : user.userTypeCd, | ||
433 | + token, | ||
434 | + }; | ||
435 | + | ||
436 | +}; | ||
437 | + | ||
262 | exports.logout = async(ctx) => { | 438 | exports.logout = async(ctx) => { |
263 | ctx.cookies.set('access_token', null, { | 439 | ctx.cookies.set('access_token', null, { |
264 | httpOnly : true, | 440 | httpOnly : true, | ... | ... |
... | @@ -5,7 +5,7 @@ const authCtrl = require('./auth.ctrl') | ... | @@ -5,7 +5,7 @@ const authCtrl = require('./auth.ctrl') |
5 | const auth = new Router() | 5 | const auth = new Router() |
6 | 6 | ||
7 | /** | 7 | /** |
8 | - * 회원가입 (email type) : 환자 회원가입 | 8 | + * 로컬 회원가입 (email type) : 환자 회원가입 |
9 | * url : http://localhost:4000/api/auth/register | 9 | * url : http://localhost:4000/api/auth/register |
10 | * request parameter : userId, password, passwordCheck | 10 | * request parameter : userId, password, passwordCheck |
11 | * return : null | 11 | * return : null |
... | @@ -21,7 +21,7 @@ auth.post('/register', authCtrl.register) | ... | @@ -21,7 +21,7 @@ auth.post('/register', authCtrl.register) |
21 | auth.get('/hospital', authCtrl.searchHospital); | 21 | auth.get('/hospital', authCtrl.searchHospital); |
22 | 22 | ||
23 | /** | 23 | /** |
24 | - * 회원가입 (email type) : 의사 회원가입 | 24 | + * 로컬 회원가입 (email type) : 의사 회원가입 |
25 | * url : http://localhost:4000/api/auth/register/doctor | 25 | * url : http://localhost:4000/api/auth/register/doctor |
26 | * request parameter : userId, password, passwordCheck, doctorInfo(File) | 26 | * request parameter : userId, password, passwordCheck, doctorInfo(File) |
27 | * return : null | 27 | * return : null |
... | @@ -29,14 +29,30 @@ auth.get('/hospital', authCtrl.searchHospital); | ... | @@ -29,14 +29,30 @@ auth.get('/hospital', authCtrl.searchHospital); |
29 | auth.post('/register/doctor', KoaBody, authCtrl.doctorRegister) | 29 | auth.post('/register/doctor', KoaBody, authCtrl.doctorRegister) |
30 | 30 | ||
31 | /** | 31 | /** |
32 | - * 로그인 (email type) | 32 | + * 로컬 로그인 (email type) |
33 | * url : http://localhost:4000/api/auth/login | 33 | * url : http://localhost:4000/api/auth/login |
34 | * request parameter : userId, password | 34 | * request parameter : userId, password |
35 | - * return : userId | 35 | + * return : token, userTypeCd |
36 | */ | 36 | */ |
37 | auth.post('/login', authCtrl.login) | 37 | auth.post('/login', authCtrl.login) |
38 | 38 | ||
39 | /** | 39 | /** |
40 | + * 소셜 회원가입(Google, Naver, Kakao) | ||
41 | + * url : http://localhost:4000/api/auth/register/${socialType} | ||
42 | + * request parameter : accessToken | ||
43 | + * return : status | ||
44 | + */ | ||
45 | +auth.post('/register/social/:socialType', authCtrl.socialRegister); | ||
46 | + | ||
47 | +/** | ||
48 | + * 소셜 로그인(Google, Naver, Kakao) | ||
49 | + * url : http://localhost:4000/api/auth/login/${socialType} | ||
50 | + * request parameter | ||
51 | + * return : token, userTypeCd | ||
52 | + */ | ||
53 | +auth.post('/login/social/:socialType', authCtrl.socialLogin); | ||
54 | + | ||
55 | +/** | ||
40 | * 로그아웃 | 56 | * 로그아웃 |
41 | * url : http://localhost:4000/api/auth/logout | 57 | * url : http://localhost:4000/api/auth/logout |
42 | * request parameter : null | 58 | * request parameter : null | ... | ... |
... | @@ -5,9 +5,10 @@ const jwt = require('jsonwebtoken'); | ... | @@ -5,9 +5,10 @@ const jwt = require('jsonwebtoken'); |
5 | const Schema = mongoose.Schema; | 5 | const Schema = mongoose.Schema; |
6 | 6 | ||
7 | const UserSchema = new Schema ({ | 7 | const UserSchema = new Schema ({ |
8 | - userId : { type: String, required : true, unique : true, lowercase : true, }, | 8 | + userId : { type: String, required : true, unique : true, lowercase : true, trim : true }, |
9 | - hashedPassword : { type : String, required : true }, | 9 | + hashedPassword : { type : String, required : true, }, |
10 | - userTypeCd : { type : String, required : true, default : 'NORMAL' }, | 10 | + userTypeCd : { type : String, required : true, default : 'NORMAL', uppercase : true, }, |
11 | + authTypeCd : { type : String, required : true, default : 'NORMAL', uppercase : true, }, | ||
11 | useYn : { type : String, default : 'W', required : true, }, | 12 | useYn : { type : String, default : 'W', required : true, }, |
12 | }); | 13 | }); |
13 | 14 | ... | ... |
... | @@ -1134,10 +1134,10 @@ | ... | @@ -1134,10 +1134,10 @@ |
1134 | dependencies: | 1134 | dependencies: |
1135 | "type-fest" "^0.20.2" | 1135 | "type-fest" "^0.20.2" |
1136 | 1136 | ||
1137 | -"google-auth-library@^7.0.0", "google-auth-library@^7.0.2", "google-auth-library@^7.6.1": | 1137 | +"google-auth-library@^7.0.0", "google-auth-library@^7.0.2", "google-auth-library@^7.10.0", "google-auth-library@^7.6.1": |
1138 | - "integrity" "sha512-HjxbJt660a+YUTYAgYor87JCuBZvjUSNBExk4bXTEaMuCn8IHSDeHmFxKqThuDPrLCiKJp8blk/Ze8f7SI4N6g==" | 1138 | + "integrity" "sha512-ICsqaU+lxMHVlDUzMrfVIEqnARw2AwBiZ/2KnNM6BcTf9Nott+Af87DTIzmlnW865p3REUP2MVL0xkPC3a61aQ==" |
1139 | - "resolved" "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.9.2.tgz" | 1139 | + "resolved" "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.10.0.tgz" |
1140 | - "version" "7.9.2" | 1140 | + "version" "7.10.0" |
1141 | dependencies: | 1141 | dependencies: |
1142 | "arrify" "^2.0.0" | 1142 | "arrify" "^2.0.0" |
1143 | "base64-js" "^1.3.0" | 1143 | "base64-js" "^1.3.0" | ... | ... |
-
Please register or login to post a comment