Skip to content
Snippets Groups Projects
Commit ac3908a6 authored by nahyun's avatar nahyun
Browse files

fix: fwt 토큰 access and refresh토큰 분리+https 인증

parent 7247113f
No related branches found
No related tags found
3 merge requests!18Secure,!17Secure,!16Secure
......@@ -3,7 +3,7 @@ const app = express();
const mongoose = require('mongoose');
const cors = require('cors');
app.use(express.urlencoded({ extended: false }));
//app.use(express.urlencoded({ extended: false }));
const passport = require('./config/passport');
//const cookieParser = require('cookie-parser');
const cookieParser = require('cookie-parser');
......@@ -15,11 +15,40 @@ require('dotenv').config();
const secretKey = process.env.JWT_SECRET; // 실제 환경에서는 환경 변수로 관리하세요.
const refreshTokenSecretKey = process.env.JWT_REFRESH_SECRET;
const https = require('https');
const fs = require('fs');
const expressSanitizer = require('express-sanitizer');
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(expressSanitizer());
app.use('/', express.static('public'));
// SSL 인증서와 개인 키 파일 경로 설정
// SSL 옵션 설정
const sslOptions = {
key: fs.readFileSync('./cert/server.key'),
cert: fs.readFileSync('./cert/server.cert'),
};
// // HTTP 서버 설정 (포트 8001)
// const HTTP_PORT = 8001;
// app.listen(HTTP_PORT, () => {
// console.log(`HTTP server started on port ${HTTP_PORT}`);
// });
// // HTTPS 서버 설정 (포트 8080)
// const HTTPS_PORT = 8080;
// https.createServer(options, app).listen(HTTPS_PORT, () => {
// console.log(`HTTPS server started on port ${HTTPS_PORT}`);
// });
//middleware
app.use(cors({
origin: "http://localhost:3000",
origin: "https://localhost:3000",
credentials: true, //쿠키전송 허용
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
//비밀번호 변경 라우트 등록
const passwordRoutes = require('./route/conf_password');
......@@ -143,6 +172,10 @@ app.get('/googlelogin/redirect',
{ expiresIn: '7d' } // 리프레시 토큰 유효 기간: 7일
);
// 토큰 로그 출력
console.log('생성된 액세스 토큰:', accessToken);
console.log('생성된 리프레시 토큰:', refreshToken);
// 사용자 데이터베이스에 리프레시 토큰 저장
req.user.refreshToken = refreshToken;
await req.user.save();
......@@ -150,18 +183,19 @@ app.get('/googlelogin/redirect',
// 쿠키에 토큰 저장
res.cookie('accessToken', accessToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
secure: true,
sameSite: 'Strict',
maxAge: 15 * 60 * 1000 // 15분
});
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
secure: true,
sameSite: 'Strict',
maxAge: 7 * 24 * 60 * 60 * 1000 // 7일
});
res.redirect(`http://localhost:3000/login#token=${token}`);
//res.redirect(`http://localhost:3000/login#token=${token}`);
res.redirect('https://localhost:3000/');
console.log(`구글 로그인 성공: ${req.user.email}`);
}
);
......@@ -218,7 +252,7 @@ app.post('/token', async (req, res) => {
res.cookie('accessToken', newAccessToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
secure: true,
sameSite: 'Strict',
maxAge: 15 * 60 * 1000 // 15분
});
......@@ -331,7 +365,7 @@ app.post('/login', async (req, res) => {
//https 환경에서만
res.cookie('accessToken', accessToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production', // 프로덕션 환경에서만 secure 플래그 활성화
secure: true, // 프로덕션 환경에서만 secure 플래그 활성화
sameSite: 'Strict', // CSRF 방지를 위해 sameSite 옵션 설정
maxAge: 3600000 // 1시간 (토큰 만료 시간과 동일하게 설정)
});
......@@ -398,6 +432,24 @@ app.get('/auth/status', authenticateToken, (req, res) => {
});
app.listen(process.env.PORT, () => {
console.log(`Server is running on http://localhost:${process.env.PORT}`);
// app.listen(process.env.PORT, () => {
// console.log(`Server is running on http://localhost:${process.env.PORT}`);
// });
// HTTPS 강제 적용 미들웨어 (선택 사항)
app.use((req, res, next) => {
if (req.secure || req.headers['x-forwarded-proto'] === 'https') {
next();
} else {
res.redirect(`https://${req.headers.host}${req.url}`);
}
});
https.createServer(sslOptions, app).listen(process.env.PORT || 8000, () => {
console.log(`HTTPS 서버가 실행 중입니다: https://localhost:${process.env.PORT || 8000}`);
});
// HTTP 서버 실행 (선택 사항)
// http.createServer(app).listen(8080, () => {
// console.log('HTTP 서버가 실행 중입니다: http://localhost:8080');
// });
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUKmvSyaI7ZwBUWv+Aip2q+ozENK8wDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMDQxNDI2MTBaFw0yNTAx
MDMxNDI2MTBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCoB4lkQ8gtZALn6xl1h/s9Ub1MuAQBJEetY5UV1gJW
2aGtICzVvWgzVGbLgBJOf2jw3EBfuAGPhYcOxP2+aOHxxf3+gp5ZWWjHMa202/F0
thvlnEZTCg0modLKOw4CNMLE6OD3mhjb7KxeCZbEWMDlnYiTBsoANQrrLeAHqUOz
c2OmCuvLHxdTpLa9KmEGqQOQRNyrrhx1lKfewTRtFHpcdY2msCooa0gBYFKpEuaY
MEqrZEG2/bqUs8gSl6woeXXIN7c18ADToyQIL6Wsy57G7e3zvAehOckAWzN2/YXU
cA2FxregTiaYdmuI89BKJ3+tRUnTt2erlsGerMSCPlp1AgMBAAGjUzBRMB0GA1Ud
DgQWBBS6ssmy7CXbAnwsL68eESy337YE3jAfBgNVHSMEGDAWgBS6ssmy7CXbAnws
L68eESy337YE3jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAx
0b9exkxjIo/wm1Rqo+DEGdB1uIvLFWTximfxY0PYCERyw+RajBPlvGlqWZw0h1rH
BjIMkLW3axPdblVgAzC1J4F2ia2qH2JTF/waM2n5RkCmDXnjhpXRCeOcrv8dEvTe
0pqM3UC9QlElQ7zmTmUIdwJjWAar/rv6niGBmmG5j2NF66J0P8Bat0lndjFfXwWI
xth/u9GROzNEc3FSkHXK0VkGj76z8zsZginLccGqmysbsWWbN3ArVSv8iJoOOYq+
5/XPNRT4POZod574hqr+2QBCgyJGjfZecWR7f7Jg3NMyAVS3i0Q9gEWdKDvTmJSx
sdd32Gq+4+jIsMm37c05
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCoB4lkQ8gtZALn
6xl1h/s9Ub1MuAQBJEetY5UV1gJW2aGtICzVvWgzVGbLgBJOf2jw3EBfuAGPhYcO
xP2+aOHxxf3+gp5ZWWjHMa202/F0thvlnEZTCg0modLKOw4CNMLE6OD3mhjb7Kxe
CZbEWMDlnYiTBsoANQrrLeAHqUOzc2OmCuvLHxdTpLa9KmEGqQOQRNyrrhx1lKfe
wTRtFHpcdY2msCooa0gBYFKpEuaYMEqrZEG2/bqUs8gSl6woeXXIN7c18ADToyQI
L6Wsy57G7e3zvAehOckAWzN2/YXUcA2FxregTiaYdmuI89BKJ3+tRUnTt2erlsGe
rMSCPlp1AgMBAAECggEACW845eYPZosLxblT2d9LekctZZIceXLvylrBy3LTeUxp
cUbR9aNXpzApQGpdvMYXHpUDUUyL2+LfsTLa23bYnuJiz0hGu1YTlcGikvnZfhfe
i58hbLavA9kItJ2pvPJ48CTyQrzGggyxJeuMaVRhalMU0MqMC4Ru60MNZei5Wik8
SZLwZJRp163QXedw5f6XJ2GLlOAnKx/prmx1DFkz8I6pruearqCtJDNLlxTqoYjR
oTfmlVSMvsObDt+SsKimQ+0t01jVNDB4LTZO1myUbHslrVFeedvrzrhvjlEirMGr
tpGFdyj/tBcPkSLl3MOPOBcLkGBrF1H0+Awi+b138QKBgQDlbVh2p0JwRe27nYWb
VaK+36ZK9yXeaRdkrWIaERFfOTLbun5amV2Sj6K1oXXDTe1WrOfmGE4cx1mSX3Qb
jLBWNKq/4Uui27f5onST54t0MUZlFOfAbRJuN6IH2sEY615apmb+0x8wVhMH4dhL
k6/94lEss7h/zadqASWyzOdYpQKBgQC7fbZNujdOvtiqwVH2hEY+tXm3kvuwzW+W
jIz4CkjmPxlIvt39h0WFGg1a6X1UYAXk4J7pxR039vcwd1Ep31TyYqoL1aYEDDiS
TgsSRrD3mlzkeqUxkamzIMgtoKzZ3U4fUMGw/z3TGlmIwS5oICqZPq6jMRONh/pZ
Vj7w4UKBkQKBgBOo+xuv2ZGlbGnXZcuZ2whgQe/KngQhHVATS4TQUZzHWgRaRtmc
qtgUVu0ZmO3Tj7MNvhGJo6fzrUlNxLVXqQS6HqeytriN+4X41eSWwuyCDHY9BF8I
+btYKRpjNIjeIofCGrFbhiCuP5M9VzuivEIVUr9x5y2MgfwjfQeFZ43BAoGAXolb
o8OSYaU/MJI7lrZJiRMOJW76c8KSUnHaHrNo4JfOUuzSmCRd/GgPddindiTYs/hC
iJL4UaC4MProtNlERtdS8Jawl/flinfJg1SbpK1zy0zAAMd2rriH1uHeZhf9bTLW
Bz4b2Va+8IKfuKcHc6+0dNqpBkMbC3K+V8ztMNECgYBo02wYaNgTbvKUBEPh/NwU
U3LhCpGcvZdVvKMiQSe2vwHs+udJ+pvIl6BPQmE8gyR9BchWnG6yGNNvzZUOvBry
Z/j+gXRq/xjtjU+SxCIS086hDUGW2vEaLGB1/V8pXuCnIY+Y41NiCVXeoe5Ve4ro
dDTrCCWZACy95J0BvmhQLQ==
-----END PRIVATE KEY-----
......@@ -8,7 +8,7 @@ const User = require('../models/user');
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: `http://localhost:${process.env.PORT}/googlelogin/redirect`
callbackURL: `https://localhost:${process.env.PORT}/googlelogin/redirect`
}, async (accessToken, refreshToken, profile, done) => {
const { id, displayName, emails} = profile;
try {
......
......@@ -4,14 +4,21 @@ require('dotenv').config();
const secretKey = process.env.JWT_SECRET;
function authenticateToken(req, res, next) {
const token = req.cookies.token; // 쿠키에서 토큰 추출
const token = req.cookies.accessToken; // 쿠키에서 토큰 추출
//const authHeader = req.headers['authorization'];
//const token = authHeader && authHeader.split(' ')[1];
console.log("토큰: ", token);
if (!token) return res.sendStatus(401);
if (!token) {
req.user = null; // 토큰이 없을 경우 null로 설정
return next();
}
jwt.verify(token, secretKey, (err, decoded) => {
if (err) return res.sendStatus(403);
if (err) {
req.user = null; // 토큰이 유효하지 않을 경우도 null로 설정
return next();
}
req.user = decoded;
next();
......
......@@ -7,6 +7,7 @@ const userSchema = new mongoose.Schema({
name: String,
password: String,
//profilePicture: String,
// 리프레시 토큰 필드 추가
});
module.exports = mongoose.model('User', userSchema);
......@@ -16,6 +16,7 @@
"dotenv": "^16.4.5",
"expres": "^0.0.5",
"express": "^4.21.1",
"express-sanitizer": "^1.0.6",
"express-session": "^1.18.1",
"jsonwebtoken": "^9.0.2",
"jwt-decode": "^4.0.0",
......@@ -589,6 +590,18 @@
"node": ">= 0.10.0"
}
},
"node_modules/express-sanitizer": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/express-sanitizer/-/express-sanitizer-1.0.6.tgz",
"integrity": "sha512-77Ruhr/NTVGE2Ecc8pH3XedpreQiHRtwA+ONON0/nJam8Re/AvkGngd8EqKb2YKCqaL4Iw+W33IJXgHgMe7xaQ==",
"license": "MIT",
"dependencies": {
"sanitizer": "0.1.3"
},
"engines": {
"node": "*"
}
},
"node_modules/express-session": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz",
......@@ -1756,6 +1769,12 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/sanitizer": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/sanitizer/-/sanitizer-0.1.3.tgz",
"integrity": "sha512-j05vL56tR90rsYqm9ZD05v6K4HI7t4yMDEvvU0x4f+IADXM9Jx1x9mzatxOs5drJq6dGhugxDW99mcPvXVLl+Q==",
"license": "Apache-2.0"
},
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
......
......@@ -7,6 +7,7 @@
"dotenv": "^16.4.5",
"expres": "^0.0.5",
"express": "^4.21.1",
"express-sanitizer": "^1.0.6",
"express-session": "^1.18.1",
"jsonwebtoken": "^9.0.2",
"jwt-decode": "^4.0.0",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment