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.
263 lines
9.1 KiB
263 lines
9.1 KiB
const jwt = require("jsonwebtoken");
|
|
const usersController = {};
|
|
|
|
/**
|
|
* 핸드폰 번호인증
|
|
*/
|
|
usersController.phoneAuth = async(req, res) => {
|
|
|
|
// POST 요청한 body에서 값을 받아옵니다.
|
|
const phone = req.body?.phone?.replace('/-/g','') ?? '';
|
|
const code = Math.floor(100000 + Math.random() * 900000)
|
|
|
|
// 핸드폰 번호값이 없는경우
|
|
if(phone.length === 0) {
|
|
return res.status(400).json({error:'핸드폰 번호를 입력하세요'});
|
|
}
|
|
|
|
// @TODO: 실제 SMS 발송 API를 이용한 인증번호 발송 처리
|
|
|
|
// 응답 데이타를 만든다
|
|
const result = {
|
|
authCode: code
|
|
}
|
|
|
|
return res.json({result})
|
|
}
|
|
|
|
/**
|
|
* 회원가입 처리
|
|
*/
|
|
usersController.userRegister = async(req, res) => {
|
|
// 받아온 데이타를 정리한다.
|
|
let login_id = req.body?.email ?? ''
|
|
let login_pass = req.body?.password ?? ''
|
|
let login_pass_confirm = req.body?.passwordConfirm ?? ''
|
|
let nickname = req.body?.nickname ?? ''
|
|
let phone = req.body?.phone ?? ''
|
|
let agree_marketing = req.body?.agreeMarketing ? 'Y' : 'N'
|
|
let privacy_agree_at = (new Date())
|
|
|
|
// model 객체 불러오기
|
|
const usersModel = loadModule('users', 'model');
|
|
|
|
// 폼검증 처리 시작
|
|
if(nickname === '') {
|
|
return res.status(400).json({error:'[닉네임]은 필수 입력값입니다'})
|
|
}
|
|
if(login_id === '') {
|
|
return res.status(400).json({error:'[이메일주소]는 필수 입력값입니다'})
|
|
}
|
|
|
|
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,}))$/;
|
|
|
|
console.log(emailRegex.test(login_id));
|
|
if(! emailRegex.test(login_id))
|
|
{
|
|
return res.status(400).json({error:'올바른 형식의 [이메일주소]가 아닙니다'})
|
|
}
|
|
|
|
// 이미 사용중인 이메일 주소인지 체크합니다.
|
|
const check1 = await usersModel.getUser(login_id, 'login_id');
|
|
if(check1 !== null) {
|
|
return res.status(400).json({error:'이미 가입된 [이메일주소] 입니다.'})
|
|
}
|
|
|
|
if(login_pass === '') {
|
|
return res.status(400).json({error:'[비밀번호]는 필수 입력값입니다'})
|
|
}
|
|
|
|
const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
|
|
if(! passwordRegex.test(login_pass)) {
|
|
return res.status(400).json({error:'[비밀번호]는 8자 이상, 하나이상의 문자,숫자 및 특수문자를 사용하셔야 합니다'})
|
|
}
|
|
|
|
if(login_pass !== login_pass_confirm)
|
|
{
|
|
return res.status(400).json({error:'[비밀번호]와 [비밀번호 확인]이 서로 다릅니다.'})
|
|
}
|
|
|
|
const result = await usersModel.addUser({
|
|
login_id,
|
|
login_pass,
|
|
phone,
|
|
nickname,
|
|
agree_marketing,
|
|
privacy_agree_at
|
|
})
|
|
|
|
if(result) {
|
|
return res.json({result: 'success'})
|
|
}
|
|
else {
|
|
return res.status(500).json({result: 'fail'})
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 사용자 로그인 처리
|
|
*/
|
|
usersController.authorize = async(req, res) => {
|
|
const loginId = req.body?.loginId ?? '',
|
|
loginPass = req.body?.loginPass ?? ''
|
|
|
|
// 아이디와 비밀번호 폼검증
|
|
if( loginId.length === 0 )
|
|
return res.status(400).json({error:'[이메일주소]를 입력하세요.'})
|
|
|
|
if( loginPass.length === 0 )
|
|
return res.status(400).json({error:'[비밀번호]를 입력하세요.'})
|
|
|
|
// user model 불러오기
|
|
const UserModel = loadModule('users', 'model')
|
|
|
|
// 해당하는 아이디의 사용자가 있는지 정보를 가져옵니다.
|
|
let user = await UserModel.getUser( loginId, 'login_id' )
|
|
|
|
// 데이타베이스에 정보가 없다면
|
|
if(user === false || user === null)
|
|
return res.status(400).json({error:'가입되지 않은 [이메일주소]이거나 [비밀번호]가 올바르지 않습니다.'})
|
|
|
|
// 비밀번호 체크를 위해 입력한 비밀번호를 암호화 합니다.
|
|
const encryptedPassword = require('sha256')(require('md5')(appConfig.secretKey + loginPass))
|
|
|
|
// DB에서 가져온 암호화된 사용자 비밀번호와 사용자가 입력한 암호화된 비밀번호가 맞지 않다면
|
|
// 아이디가 존재하지 않을 경우와 비밀번호가 다를 경우의 에러메시지를 동일하게 사용합니다.
|
|
if(user.login_pass !== encryptedPassword)
|
|
return res.status(400).json({error:'가입되지 않은 [이메일주소]이거나 [비밀번호]가 올바르지 않습니다.'})
|
|
|
|
// 회원상태가 정상이 아닌경우
|
|
if(user.status !== 'Y')
|
|
return res.status(400).json({error:'가입되지 않은 [이메일주소]이거나 [비밀번호]가 올바르지 않습니다.'})
|
|
|
|
// 모든 검증이 완료되면 토큰을 생성하여 반환한다.
|
|
return await UserModel.responseToken(user)
|
|
.then(result => {
|
|
return res.json(result);
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 토큰 재생성
|
|
*/
|
|
usersController.refreshToken = async (req, res) => {
|
|
const refreshToken = req.body?.refreshToken ?? ''
|
|
const jwt = require('jsonwebtoken');
|
|
|
|
// 올바른 refreshToken 정보가 없을경우
|
|
if (!refreshToken)
|
|
return res.status(401).json({error: '사용자 로그인 정보가 유효하지 않습니다'});
|
|
|
|
// verify 메서드를 이용해서 refresh token을 검증합니다.
|
|
await jwt.verify(refreshToken, appConfig.secretKey, async (error, decoded) => {
|
|
|
|
// 검증 오류 발생시 오류를 반환합니다.
|
|
if (error) {
|
|
if (error.name === 'TokenExpiredError') {
|
|
return res.status(401).json({error: '사용자 로그인 정보가 유효하지 않습니다'});
|
|
}
|
|
return res.status(401).json({error: '사용자 로그인 정보가 유효하지 않습니다',});
|
|
}
|
|
|
|
const UserModel = loadModule('users', 'model')
|
|
|
|
// 검증 오류가 없는 경우 새로운 토큰을 발급해줍니다.
|
|
let user = {};
|
|
try {
|
|
// user model 불러오기
|
|
|
|
|
|
// 사용자 정보 가져오기
|
|
await UserModel.getUser(decoded.id, 'id')
|
|
.then((res) => {
|
|
user = res;
|
|
});
|
|
} catch {
|
|
user = null;
|
|
}
|
|
|
|
// 회원상태가 정상이 아닌경우
|
|
if (user === {} || user === null || user.status !== 'Y')
|
|
return res.status(400).json({error: '가입되지 않은 [이메일주소]이거나 [비밀번호]가 올바르지 않습니다.'});
|
|
|
|
// 새로운 accessToken 과 refreshToken 을 발급한다.
|
|
return await UserModel.responseToken(user).then((json) => {
|
|
return res.status(200).json(json);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 로그인한 사용자의 정보 가져오기
|
|
*/
|
|
usersController.getInfo = async(req, res) => {
|
|
// 미들웨어를 통해 헤더를 통해 전송받은 accessToken을 이용해 현재 로그인 사용자의 PK를 가져온다.
|
|
const loginUserId = req.loginUser?.id ?? 0
|
|
|
|
// 로그인 되지 않앗거나 잘못된 PK의 경우
|
|
if(loginUserId === undefined || loginUserId < 1) {
|
|
return res.status(400).json({error:'잘못된 접근입니다'})
|
|
}
|
|
|
|
// user model 불러오기
|
|
const UserModel = loadModule('users', 'model')
|
|
|
|
let user = {}
|
|
try {
|
|
await UserModel.getUser( loginUserId, 'id' ).then(res => {user = res})
|
|
}
|
|
catch {
|
|
user = null
|
|
}
|
|
|
|
// 회원상태가 정상이 아닌경우
|
|
if(user === {} || user === null || user.status !== 'Y')
|
|
return res.status(400).json({code:'AUTH.ERR007', error:"탈퇴한 회원이거나 접근이 거부된 회원입니다."})
|
|
|
|
return res.json(user);
|
|
}
|
|
|
|
/**
|
|
* 로그인한 사용자의 정보를 체크하는 미들웨어
|
|
*/
|
|
usersController.loginUserCheck = async(req, res, next) => {
|
|
// JWT 패키지 로드
|
|
const jwt = require('jsonwebtoken');
|
|
const ipToInt = require('ip-to-int');
|
|
|
|
|
|
// Default 값을 지정한다
|
|
req.loginUser = {
|
|
id: 0,
|
|
ip: ipToInt(req.headers['x-forwarded-for'] || req.connection.remoteAddress).toInt()
|
|
}
|
|
|
|
// 만약 토큰 재발급요청이거나, 로그인 요청의 경우 실행하지 않는다.
|
|
if(req.path === '/users/authorize/token' || req.path === '/users/authorize') {
|
|
return next();
|
|
}
|
|
|
|
// 헤더에 포함된 accessToken 값을 가져온다.
|
|
let accessToken = req.headers['Authorization'] || req.headers['authorization'];
|
|
// AccessToken이 없는 경우 비로그인 상태이므로 그대로 넘어간다.
|
|
if(! accessToken) return next();
|
|
|
|
// AccessToken 값에서 "Bearer" 값을 제거한다.
|
|
accessToken = accessToken.replace("Bearer ",'')
|
|
|
|
// AccessToken을 검증한다.
|
|
await jwt.verify(accessToken, appConfig.secretKey, async(error, decoded) => {
|
|
if (error) {
|
|
return res.status(401).json({error: '토큰 유효기간이 만료되었습니다.'});
|
|
}
|
|
else {
|
|
// 토큰검증에 성공한경우, req.loginUser 객체의 id 값을 복호화한 회원PK값으로 변경한다.
|
|
req.loginUser.id = decoded.id;
|
|
|
|
return next();
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
module.exports = usersController;
|