Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/db.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const pool = mysql.createPool({
user: process.env.DB_USER || 'root', // user 이름
port: process.env.DB_PORT || '3306', // 포트 번호
database: process.env.DB_TABLE || 'myplace_dev', // 데이터베이스 이름
password: process.env.DB_PASSWORD || '111111', // 비밀번호
password: process.env.DB_PASSWORD || '1111', // 비밀번호
waitForConnections: true,
// Pool에 획득할 수 있는 connection이 없을 때,
// true면 요청을 queue에 넣고 connection을 사용할 수 있게 되면 요청을 실행하며, false이면 즉시 오류를 내보내고 다시 요청
Expand Down
13 changes: 10 additions & 3 deletions config/jwt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@ import dotenv from 'dotenv'
dotenv.config()

export const jwtConfig = {
secretKey: process.env.TOKKEN_SECRET,
secretKey: process.env.TOKEN_SECRET,
options: {
algorithm: process.env.TOKKEN_ALGORITHM,
expiresIn: process.env.TOKKEN_EXPIRE,
algorithm: process.env.TOKEN_ALGORITHM,
expiresIn: process.env.TOKEN_EXPIRE,
},
}
export const jwtRefreshConfig = {
secretKey: process.env.TOKEN_SECRET,
options: {
algorithm: process.env.TOKEN_ALGORITHM,
expiresIn: process.env.TOKEN_REFRESH_EXPIRE,
},
}
8 changes: 7 additions & 1 deletion config/response.status.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ export const status = {
code: 'AUTH2001',
message: '구글 로그인 완료!',
},
TOKEN_LOGIN_SUCCESS: {
status: 200,
isSuccess: true,
code: 'AUTH2001',
message: '토큰 로그인 완료!',
},
REGISTER_SUCCESS: {
status: 200,
isSuccess: true,
Expand Down Expand Up @@ -103,7 +109,7 @@ export const status = {
status: 400,
isSuccess: false,
code: 'TOEKN4002',
message: '유효하지 않은 토큰',
message: '유효하지 않은 토큰. 재로그인 필요',
},
TOKEN_SIGNITURE: {
status: 400,
Expand Down
2 changes: 2 additions & 0 deletions ecosystem.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ module.exports = {
error: 'logs/pm2/myplace.error.log',
//merge_logs: true,
autorestart: true,
ignore_watch: ['node_modules'],
watch: true,
// max_memory_restart: "512M",
time: true,
},
],
}
82 changes: 60 additions & 22 deletions src/controllers/auth.controller.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,81 @@
import { response } from '../../config/response.js'
import { status } from '../../config/response.status.js'
import { tokenVerify } from '../middlewares/jwt.middleware.js'
import { tokenVerify, tokenCheck } from '../middlewares/jwt.middleware.js'

import { kakaoLogin, googleLogin } from '../services/auth.service.js'

import Axios from 'axios'

//임시
import dotenv from 'dotenv'
import {
newRefreshTokenLogin,
newTokenLogin,
tokenLogin,
} from '../providers/auth.provider.js'
dotenv.config()

export const authLogin = async (req, res) => {
try {
const provider = req.body.provider
if (provider == '0') {
console.log('카카오 로그인 요청!')
//토큰 확인
const tokenResult = await tokenCheck(req, res)

//Access토큰이 유효한 경우
if (tokenResult.status == 1) {
console.log('Token로그인 요청: ', tokenResult)
return res.send(
response(
status.KAKAO_LOGIN_SUCCESS,
await kakaoLogin(req.headers, req.body),
),
response(status.TOKEN_LOGIN_SUCCESS, await tokenLogin(tokenResult)),
)
}
//Access토큰은 만료, Refresh토큰이 유효한 경우
else if (tokenResult.status == 2) {
console.log('newToken로그인 요청: ', tokenResult)
return res.send(
response(status.TOKEN_LOGIN_SUCCESS, await newTokenLogin(tokenResult)),
)
} else if (provider == '1') {
console.log('구글 로그인 요청!')
}
//Access토큰은 유효, Refresh토큰이 만료된 경우
else if (tokenResult.status == 3) {
console.log('newRefreshToken로그인 요청: ', tokenResult)
return res.send(
response(
status.GOOGLE_LOGIN_SUCCESS,
await googleLogin(req.headers, req.body),
status.TOKEN_LOGIN_SUCCESS,
await newRefreshTokenLogin(tokenResult),
),
)
} //else if (provider == 2) {
// console.log('애플 로그인 요청!')
// res.send(
// response(
// status.REGISTER_SUCCESS,
// await appleLogin(req.headers, req.body),
// ),
// )
// }
return res.send(response(status.INVAILD_PROVIDER, null))
}
//Access, Refresh 토큰이 없거나, 만료,이상인 경우
else if (tokenResult.status == -1) {
//return res.send(response(status.TOKEN_INVAILD, tokenResult.message))
const provider = req.body.provider
if (provider == '0') {
console.log('카카오 로그인 요청!')
return res.send(
response(
status.KAKAO_LOGIN_SUCCESS,
await kakaoLogin(req.headers, req.body),
),
)
} else if (provider == '1') {
console.log('구글 로그인 요청!')
return res.send(
response(
status.GOOGLE_LOGIN_SUCCESS,
await googleLogin(req.headers, req.body),
),
)
} //else if (provider == 2) {
// console.log('애플 로그인 요청!')
// res.send(
// response(
// status.REGISTER_SUCCESS,
// await appleLogin(req.headers, req.body),
// ),
// )
// }
return res.send(response(status.INVAILD_PROVIDER, null))
}
return res.send(response(status.TOKEN_ERROR, null))
} catch (err) {
console.log('LoginController Err: ', err)
return res.send(response(status.CONTROL_ERROR, null))
Expand Down Expand Up @@ -66,6 +103,7 @@ export const authGoogleRedirectTest = async (req, res) => {
//임시
export const authJWT = async (req, res) => {
try {
console.log(req.headers['token'])
return res.send(
response(status.SUCCESS, await tokenVerify(req.headers['token'])),
)
Expand Down
5 changes: 3 additions & 2 deletions src/dtos/auth.dto.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// login response DTO
export const loginResponseDTO = (user, access_token) => {
export const loginResponseDTO = (user, accessToken, refreshToken) => {
user = user[0]
console.log(user)
return {
userId: user.id,
email: user.email,
username: user.username,
profile_img: user.profile_img,
access_Token: access_token,
accessToken: accessToken,
refreshToken: refreshToken,
}
}
134 changes: 129 additions & 5 deletions src/middlewares/jwt.middleware.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { pool } from '../../config/db.config'
import jwt from 'jsonwebtoken'
import { jwtConfig } from '../../config/jwt.config'
import { jwtConfig, jwtRefreshConfig } from '../../config/jwt.config'
import { BaseError } from '../../config/error'
import { status } from '../../config/response.status'

Expand All @@ -11,11 +12,16 @@ export const tokenSign = async (user) => {
username: user.username,
email: user.email,
}
console.log(user)
const result = jwt.sign(payload, jwtConfig.secretKey, jwtConfig.options)
return result
}

export const tokenRefreshSign = async () => {
//현재는 username와 email을 payload로 넣었지만 필요한 값을 넣으면 됨!
const result = jwt.sign({}, jwtConfig.secretKey, jwtRefreshConfig.options)
return result
}

//토큰 인증
export const tokenVerify = async (token) => {
let decoded
Expand All @@ -25,17 +31,135 @@ export const tokenVerify = async (token) => {
} catch (err) {
if (err.message === 'jwt expired') {
console.log('TOKEN_EXPIRED')
throw new BaseError(status.TOKEN_EXPIRED)
return 'TOKEN_EXPIRED'
} else if (err.message === 'invalid token') {
console.log('TOKEN_INVALID')
throw new BaseError(status.TOKEN_INVAILD)
return 'TOKEN_INVALID'
} else if (err.message === 'invalid signature') {
console.log('TOKEN_SIGNITURE')
throw new BaseError(status.TOKEN_SIGNITURE)
return 'TOKEN_INVAILD_SIGNITURE'
} else if (err.message === 'jwt malformed') {
console.log('TOKEN_INVALID')
return 'TOKEN_INVALID'
} else {
console.log(err.message)
throw new BaseError(status.TOKEN_ERROR)
}
}
return decoded
}

//토큰 인증
export const tokenResponseDTO = (
status = -1,
result = null,
refresh = null,
access = null,
userId = null,
) => {
return {
status: status, //-1 재로그인, 1 토큰 로그인 & refresh 재발급 후 로그인, 2 access 재발급 후 로그인
result: result,
refresh: refresh, //로그인 시 반환할 refresh 토큰. 만료시 자동 재발급
access: access, //로그인 시 반환할 refresh 토큰. 만료시 자동 재발급
userId: userId, //access 만료 시 refresh를 통해 userId 제공 -> 로그인 진행
}
}

export const tokenCheck = async (req, res) => {
if (req.headers['access'] === undefined)
throw new BaseError(status.TOKEN_ERROR)
const accessToken = await tokenVerify(req.headers['access'])
const refreshToken = await tokenVerify(req.headers['refresh']) // *실제로는 DB 조회
console.log(accessToken, refreshToken)
if (
accessToken === 'TOKEN_INVALID' ||
accessToken === 'TOKEN_INVAILD_SIGNITURE' ||
refreshToken === 'TOKEN_INVAILD_SIGNITURE'
) {
console.log('case 0')
return tokenResponseDTO(-1, '유효하지 않은 토큰. 재로그인 필요.')
}
if (accessToken === 'TOKEN_EXPIRED') {
if (refreshToken === 'TOKEN_EXPIRED') {
console.log('CASE 1-1')
// case1: access token과 refresh token 모두가 만료된 경우
return tokenResponseDTO(-1, '토큰 만료. 재로그인 필요.')
} else if (refreshToken === 'TOKEN_INVALID') {
console.log('CASE 1-2')
// case1: access token과 refresh token 모두가 만료된 경우
return tokenResponseDTO(-1, '토큰 만료. 재로그인 필요.')
} else {
console.log('CASE 2')
// case2: access token은 만료됐지만, refresh token은 유효한 경우
/**
* DB를 조회해서 payload에 담을 값들을 가져오는 로직
*/
const conn = await pool.getConnection()
const [user] = await conn.query(
`SELECT user_id FROM oauthid WHERE access_token = '${req.headers['refresh']}';`,
)
console.log(user[0])
// res.cookie('access', newAccessToken)
// req.cookies.access = newAccessToken
const newAccessToken = await tokenSign(user[0])
res.set('access', newAccessToken)
return tokenResponseDTO(
2,
accessToken,
req.headers['refresh'],
newAccessToken,
user[0].user_id,
)
}
} else {
if (refreshToken === 'TOKEN_INVALID' || refreshToken === 'TOKEN_EXPIRED') {
console.log('CASE 3')
// case3: access token은 유효하지만, refresh token은 만료된 경우
let conn
try {
const newRefreshToken = await tokenRefreshSign()
conn = await pool.getConnection()
await conn.beginTransaction()
console.log(accessToken)
const [user] = await conn.query(
'SELECT * FROM USER WHERE id = ?;',
accessToken.id,
)
console.log(user[0])
await conn.query(
`UPDATE oauthid
SET access_token = '${newRefreshToken}'
WHERE user_id = ${user[0].id};`,
)
await conn.commit()
conn.release()
//res.cookie('refresh', newRefreshToken)
//req.cookies.refresh = newRefreshToken
res.set('access', newRefreshToken)
return tokenResponseDTO(1, accessToken, newRefreshToken, user[0].id)
} catch (err) {
console.log('JWT: ', err)

try {
if (conn) {
await conn.rollback()
}
} catch (rollbackError) {
console.error('Error in rollback:', rollbackError)
}

throw new BaseError(status.PARAMETER_IS_WRONG)
}
} else {
// case4: accesss token과 refresh token 모두가 유효한 경우
console.log('Case4')
return tokenResponseDTO(
1,
accessToken,
req.headers['refresh'],
req.headers['access'],
)
}
}
}
8 changes: 7 additions & 1 deletion src/models/auth.dao.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const addUser = async (
profileImage,
provider,
oauthId,
refresh,
) => {
let conn
try {
Expand All @@ -60,7 +61,12 @@ export const addUser = async (
email,
profileImage,
])
await conn.query(insertOauthSql, [result[0].insertId, oauthId, provider])
await conn.query(insertOauthSql, [
result[0].insertId,
oauthId,
provider,
refresh,
])
await conn.commit()
conn.release()
return result[0].insertId
Expand Down
8 changes: 5 additions & 3 deletions src/models/auth.sql.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ export const insertUserSql =

//유저 oauth정보 저장
export const insertOauthSql =
'INSERT INTO oauthid(user_id, access_token, provider) VALUES(?,?,? );'
'INSERT INTO oauthid(user_id, id, provider,access_token) VALUES(?,?,?,? );'

export const selectUser = `
SELECT * FROM user WHERE id = ?`
export const insertOauthRefreshSql =
'UPDATE oauthid SET access_token = ? WHERE user_id = ?;'

export const selectUser = `
SELECT * FROM user WHERE id = ?;`
Loading