You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
9.1 KiB

12 months ago
  1. const jwt = require("jsonwebtoken");
  2. const usersController = {};
  3. /**
  4. * 핸드폰 번호인증
  5. */
  6. usersController.phoneAuth = async(req, res) => {
  7. // POST 요청한 body에서 값을 받아옵니다.
  8. const phone = req.body?.phone?.replace('/-/g','') ?? '';
  9. const code = Math.floor(100000 + Math.random() * 900000)
  10. // 핸드폰 번호값이 없는경우
  11. if(phone.length === 0) {
  12. return res.status(400).json({error:'핸드폰 번호를 입력하세요'});
  13. }
  14. // @TODO: 실제 SMS 발송 API를 이용한 인증번호 발송 처리
  15. // 응답 데이타를 만든다
  16. const result = {
  17. authCode: code
  18. }
  19. return res.json({result})
  20. }
  21. /**
  22. * 회원가입 처리
  23. */
  24. usersController.userRegister = async(req, res) => {
  25. // 받아온 데이타를 정리한다.
  26. let login_id = req.body?.email ?? ''
  27. let login_pass = req.body?.password ?? ''
  28. let login_pass_confirm = req.body?.passwordConfirm ?? ''
  29. let nickname = req.body?.nickname ?? ''
  30. let phone = req.body?.phone ?? ''
  31. let agree_marketing = req.body?.agreeMarketing ? 'Y' : 'N'
  32. let privacy_agree_at = (new Date())
  33. // model 객체 불러오기
  34. const usersModel = loadModule('users', 'model');
  35. // 폼검증 처리 시작
  36. if(nickname === '') {
  37. return res.status(400).json({error:'[닉네임]은 필수 입력값입니다'})
  38. }
  39. if(login_id === '') {
  40. return res.status(400).json({error:'[이메일주소]는 필수 입력값입니다'})
  41. }
  42. const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  43. console.log(emailRegex.test(login_id));
  44. if(! emailRegex.test(login_id))
  45. {
  46. return res.status(400).json({error:'올바른 형식의 [이메일주소]가 아닙니다'})
  47. }
  48. // 이미 사용중인 이메일 주소인지 체크합니다.
  49. const check1 = await usersModel.getUser(login_id, 'login_id');
  50. if(check1 !== null) {
  51. return res.status(400).json({error:'이미 가입된 [이메일주소] 입니다.'})
  52. }
  53. if(login_pass === '') {
  54. return res.status(400).json({error:'[비밀번호]는 필수 입력값입니다'})
  55. }
  56. const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&amp;])[A-Za-z\d@$!%*#?&amp;]{8,}$/;
  57. if(! passwordRegex.test(login_pass)) {
  58. return res.status(400).json({error:'[비밀번호]는 8자 이상, 하나이상의 문자,숫자 및 특수문자를 사용하셔야 합니다'})
  59. }
  60. if(login_pass !== login_pass_confirm)
  61. {
  62. return res.status(400).json({error:'[비밀번호]와 [비밀번호 확인]이 서로 다릅니다.'})
  63. }
  64. const result = await usersModel.addUser({
  65. login_id,
  66. login_pass,
  67. phone,
  68. nickname,
  69. agree_marketing,
  70. privacy_agree_at
  71. })
  72. if(result) {
  73. return res.json({result: 'success'})
  74. }
  75. else {
  76. return res.status(500).json({result: 'fail'})
  77. }
  78. }
  79. /**
  80. * 사용자 로그인 처리
  81. */
  82. usersController.authorize = async(req, res) => {
  83. const loginId = req.body?.loginId ?? '',
  84. loginPass = req.body?.loginPass ?? ''
  85. // 아이디와 비밀번호 폼검증
  86. if( loginId.length === 0 )
  87. return res.status(400).json({error:'[이메일주소]를 입력하세요.'})
  88. if( loginPass.length === 0 )
  89. return res.status(400).json({error:'[비밀번호]를 입력하세요.'})
  90. // user model 불러오기
  91. const UserModel = loadModule('users', 'model')
  92. // 해당하는 아이디의 사용자가 있는지 정보를 가져옵니다.
  93. let user = await UserModel.getUser( loginId, 'login_id' )
  94. // 데이타베이스에 정보가 없다면
  95. if(user === false || user === null)
  96. return res.status(400).json({error:'가입되지 않은 [이메일주소]이거나 [비밀번호]가 올바르지 않습니다.'})
  97. // 비밀번호 체크를 위해 입력한 비밀번호를 암호화 합니다.
  98. const encryptedPassword = require('sha256')(require('md5')(appConfig.secretKey + loginPass))
  99. // DB에서 가져온 암호화된 사용자 비밀번호와 사용자가 입력한 암호화된 비밀번호가 맞지 않다면
  100. // 아이디가 존재하지 않을 경우와 비밀번호가 다를 경우의 에러메시지를 동일하게 사용합니다.
  101. if(user.login_pass !== encryptedPassword)
  102. return res.status(400).json({error:'가입되지 않은 [이메일주소]이거나 [비밀번호]가 올바르지 않습니다.'})
  103. // 회원상태가 정상이 아닌경우
  104. if(user.status !== 'Y')
  105. return res.status(400).json({error:'가입되지 않은 [이메일주소]이거나 [비밀번호]가 올바르지 않습니다.'})
  106. // 모든 검증이 완료되면 토큰을 생성하여 반환한다.
  107. return await UserModel.responseToken(user)
  108. .then(result => {
  109. return res.json(result);
  110. })
  111. }
  112. /**
  113. * 토큰 재생성
  114. */
  115. usersController.refreshToken = async (req, res) => {
  116. const refreshToken = req.body?.refreshToken ?? ''
  117. const jwt = require('jsonwebtoken');
  118. // 올바른 refreshToken 정보가 없을경우
  119. if (!refreshToken)
  120. return res.status(401).json({error: '사용자 로그인 정보가 유효하지 않습니다'});
  121. // verify 메서드를 이용해서 refresh token을 검증합니다.
  122. await jwt.verify(refreshToken, appConfig.secretKey, async (error, decoded) => {
  123. // 검증 오류 발생시 오류를 반환합니다.
  124. if (error) {
  125. if (error.name === 'TokenExpiredError') {
  126. return res.status(401).json({error: '사용자 로그인 정보가 유효하지 않습니다'});
  127. }
  128. return res.status(401).json({error: '사용자 로그인 정보가 유효하지 않습니다',});
  129. }
  130. const UserModel = loadModule('users', 'model')
  131. // 검증 오류가 없는 경우 새로운 토큰을 발급해줍니다.
  132. let user = {};
  133. try {
  134. // user model 불러오기
  135. // 사용자 정보 가져오기
  136. await UserModel.getUser(decoded.id, 'id')
  137. .then((res) => {
  138. user = res;
  139. });
  140. } catch {
  141. user = null;
  142. }
  143. // 회원상태가 정상이 아닌경우
  144. if (user === {} || user === null || user.status !== 'Y')
  145. return res.status(400).json({error: '가입되지 않은 [이메일주소]이거나 [비밀번호]가 올바르지 않습니다.'});
  146. // 새로운 accessToken 과 refreshToken 을 발급한다.
  147. return await UserModel.responseToken(user).then((json) => {
  148. return res.status(200).json(json);
  149. });
  150. });
  151. }
  152. /**
  153. * 로그인한 사용자의 정보 가져오기
  154. */
  155. usersController.getInfo = async(req, res) => {
  156. // 미들웨어를 통해 헤더를 통해 전송받은 accessToken을 이용해 현재 로그인 사용자의 PK를 가져온다.
  157. const loginUserId = req.loginUser?.id ?? 0
  158. // 로그인 되지 않앗거나 잘못된 PK의 경우
  159. if(loginUserId === undefined || loginUserId < 1) {
  160. return res.status(400).json({error:'잘못된 접근입니다'})
  161. }
  162. // user model 불러오기
  163. const UserModel = loadModule('users', 'model')
  164. let user = {}
  165. try {
  166. await UserModel.getUser( loginUserId, 'id' ).then(res => {user = res})
  167. }
  168. catch {
  169. user = null
  170. }
  171. // 회원상태가 정상이 아닌경우
  172. if(user === {} || user === null || user.status !== 'Y')
  173. return res.status(400).json({code:'AUTH.ERR007', error:"탈퇴한 회원이거나 접근이 거부된 회원입니다."})
  174. return res.json(user);
  175. }
  176. /**
  177. * 로그인한 사용자의 정보를 체크하는 미들웨어
  178. */
  179. usersController.loginUserCheck = async(req, res, next) => {
  180. // JWT 패키지 로드
  181. const jwt = require('jsonwebtoken');
  182. const ipToInt = require('ip-to-int');
  183. // Default 값을 지정한다
  184. req.loginUser = {
  185. id: 0,
  186. ip: ipToInt(req.headers['x-forwarded-for'] || req.connection.remoteAddress).toInt()
  187. }
  188. // 만약 토큰 재발급요청이거나, 로그인 요청의 경우 실행하지 않는다.
  189. if(req.path === '/users/authorize/token' || req.path === '/users/authorize') {
  190. return next();
  191. }
  192. // 헤더에 포함된 accessToken 값을 가져온다.
  193. let accessToken = req.headers['Authorization'] || req.headers['authorization'];
  194. // AccessToken이 없는 경우 비로그인 상태이므로 그대로 넘어간다.
  195. if(! accessToken) return next();
  196. // AccessToken 값에서 "Bearer" 값을 제거한다.
  197. accessToken = accessToken.replace("Bearer ",'')
  198. // AccessToken을 검증한다.
  199. await jwt.verify(accessToken, appConfig.secretKey, async(error, decoded) => {
  200. if (error) {
  201. return res.status(401).json({error: '토큰 유효기간이 만료되었습니다.'});
  202. }
  203. else {
  204. // 토큰검증에 성공한경우, req.loginUser 객체의 id 값을 복호화한 회원PK값으로 변경한다.
  205. req.loginUser.id = decoded.id;
  206. return next();
  207. }
  208. });
  209. }
  210. module.exports = usersController;