해결된 질문
24.06.23 18:00 작성
·
420
·
수정됨
0
안녕하세요 선생님
배포테스트할때 클라이언트에서 api호출하면 쿠키가 전달되지 않고있습니다.
클라이언트에서는
credentials: 'include'를 적용했고
const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/user/setting`, {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userSettingObj),
});
if (response.ok) {
const sessionUpdateInfo = await response.json();
await updateSession(sessionUpdateInfo);
router.push('/');
}
서버에서는
const express = require('express');
const cors = require('cors');
const passport = require('passport');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
const morgan = require('morgan');
const path = require('path');
const hpp = require('hpp');
const helmet = require('helmet');
const postRouter = require('./routes/post');
const postsRouter = require('./routes/posts');
const userRouter = require('./routes/user');
const usersRouter = require('./routes/users');
const db = require('./models');
const passportConfig = require('./passport');
dotenv.config();
const app = express();
db.sequelize.sync()
.then(() => { console.log('db 연결 성공') })
.catch(console.error);
passportConfig();
if (process.env.NODE_ENV === 'production') {
app.use(morgan('combined'));
app.use(hpp());
app.use(helmet());
} else {
app.use(morgan('dev'));
}
app.use(
cors({
origin: ['http://localhost:3000', 'whatisyourmbti.com', 'http://43.201.56.221'], // true or * // access-control-allow-origin가 true된다. --> 다른 도메인끼리 api 요청
credentials: true, // access-control-allow-credential가 true된다. --> 다른 도메인끼리 쿠키 전달
method: '*',
})
);
// 프론트에서 보낸 정보를 req.body에 넣어준다. 순서 중요!
app.use(express.json()); // json 형식으로 보냈을때 데이터 처리해줌
app.use(express.urlencoded({ extended: true })); // form submit으로 보냈을 때 데이터 처리해줌
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
}
}));
app.use(passport.initialize());
app.use(passport.session());
app.use((req, res, next) => {
console.log('Session ID:', req.sessionID);
console.log('Cookies:', req.cookies);
console.log('Signed Cookies:', req.signedCookies);
next();
});
app.get('/', (req, res) => {
res.send('hello express');
});
app.get('/api', (req, res) => {
res.send('hello api');
});
app.use('/post', postRouter);
app.use('/posts', postsRouter);
app.use('/user', userRouter);
app.use('/users', usersRouter);
app.listen(80, () => {
console.log('서버 실행 중!');
});
credentials: true, 쿠키옵션을 설정해주었는데
0|app | Session ID:---------------------------- U8DRuillNv2DBRmexmO1mZZ7fGJeWXCw
0|app | Cookies:------------------------------- [Object: null prototype] {}
0|app | Signed Cookies:------------------------ [Object: null prototype] {}
이런식으로 쿠키값이 전달되고 있지 않아서
유저 정보가 필요한(로그인 확인)로직에서 401에러가 떨어지게 됩니다.
app.use(session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
}
}));
위부분들을 검색해보고 바꿔보기도 했는데, 잘안되더라구요.
클라이언트의 ip는 http://43.201.56.221입니다.
쿠키는 로그인 후 프론트서버에서 브라우저에 삽입해주고 있습니다.
console.log(`${process.env.NEXT_PUBLIC_BASE_URL}/user/login ---------------------login api`);
const authResponse = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/user/login`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...credentials
}),
}
);
// 프론트서버에서 백엔드서버의 로그인 토큰을 받아온것. 토큰은 문자열이라서
// cookie라이브러리로 객체로 만들어준다.
let setCookie = authResponse.headers.get('Set-Cookie');
console.log('set-cookie', setCookie);
if (setCookie) {
const parsed = cookie.parse(setCookie);
console.log(parsed, '---------------parsed cookie');
// 브론트서버에서 브라우저에 쿠키를 심어준다.
// 프론트서버에 쿠키를 심으면 안된다! 왜냐하면 프론트서버는 서버라서 공용이다.
// 여러 브라우저가 전부 프론트서버르 바라본다. 개인정보 유출 문제 발생할 수 있다.
cookies().set('connect.sid', parsed['connect.sid'], parsed); // parsed = 나머지 옵션들
}
console.log(authResponse, '--------------------------------authResponse');
let user = await authResponse.json();
console.log(user, '--------------------------------user');
// console.lo(authResponse);
if (!authResponse.ok) {
return null;
}
// return user object with the their profile data
return {
...user,
email: user.email,
name: user.nickname,
image: user.image,
id: user.id,
}
} catch (err) {
console.error('로그인 에러', err);
}
그리고 cors에러는 발생하지 않고있습니다.
혹시 수정해야할 코드나, 참고해야할 부분이 있다면 알려주시면 감사하겠습니다.
답변 2
0
2024. 06. 24. 18:22
넵그렇습니다.
서버 도메인도 맞췄었습니다.
app.use(session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production', // 프로덕션 환경에서만 secure 적용
sameSite: process.env.NODE_ENV === 'production' ? 'None' : 'Lax', // 크로스 도메인 설정
domain: process.env.NODE_ENV === 'production' ? '.zzimzzim.com' : undefined // 프로덕션 도메인 설정
}
}));
이렇게 하고 클라이언트에선 요청할데 크리덴셜스 추가해서 했었습니다.
그럼에도 쿠키가 전달안됐어서
지금은
프론트: 로컬,
백엔드: api.xxx.com
에서 테스트 하고있으며
이 답변을 참고해서 진행했었습니다!
2024. 06. 24. 19:15
지금 https는 적용하셨나요? 그리고 로그인 시 쿠키가 네트워크 탭에 보입니다. 거기서 Domain, Secure 이런 거 다 맞는지 확인하세요. 쿠키 문제는 무조건 개인의 실수일 수밖에 없습니다. 네트워크 탭과 비교해보시면 됩니다.
2024. 06. 24. 22:30
그렇다면 https://www.inflearn.com/questions/1106691/api-%EC%9A%94%EC%B2%AD-%EC%8B%9C-cookie-%EB%B3%B4%EB%82%B4%EB%8A%94-%EA%B2%83%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A7%88%EB%AC%B8
여기에 답변해주신 내용은
프론트: 로컬,
백엔드: ec2서버로
도메인이 달라서 해주신 답변이고,
지금 저와같이 도메인이 같게 한 상태라면 credentials 옵션맞으로 되야하는거군요... 혹시 https작업하지 않아서 발생할수도 있는걸까요? 아무리해봐도 안되서 위위 같이 돌아간건데 좀더 작업해보면서 찾아보도록 하겠습니다.
정말 감사합니다.
2024. 06. 25. 11:27
선생님 바쁘실텐데 소중한 답변 감사합니다.
그리고 죄송합니다
제가 정말 바보같은 실수를 했었더라구요..
제가 이 강의랑 넥스트강의를 같이 보면서 작업을 했는데 넥스트 강의에서 쿠키를 심어줄때 그냥 쿠키만 심어주고나서 잊고있다가 이번에 선생님이 답변주신 네트워크 > 쿠키탭을 보고 이상하다여겨서 봤더니 쿠키심을때 따로 값을 안주고 그냥 심기만해서 발생한 문제였습니다... ㅠ
담부턴 좀 더 살피고 질문할 수 있도록 하겠습니다.
감사합니다.
0
안녕하세요, 인프런 AI 인턴입니다.
챠챠_님의 문제는 클라이언트에서 API 호출 시 쿠키가 제대로 전달되지 않아 발생하는 것으로 보입니다. 이 문제는 특히 프로덕션 환경에서 CORS(Cross-Origin Resource Sharing) 설정과 쿠키 설정에 따라서 발생할 수 있습니다. 쿠키가 브라우저에 저장되지 않거나, 서버에 전달되지 않는 경우가 주 원인일 수 있습니다.
문제 해결을 위해 확인해야 할 핵심 포인트는 다음과 같습니다:
1. CORS 설정: Access-Control-Allow-Credentials
헤더와 Access-Control-Allow-Origin
헤더 설정이 브라우저에 제대로 전달되고 있는지 확인하세요. credentials: true
는 올바르게 설정하셨으나, origin
설정에서 모든 클라이언트의 URL이 정확하게 매칭되는지 확인해야 합니다. origin: true
를 사용하면 요청의 origin
헤더값을 그대로 반환해주어 동적으로 허용할 수 있으나, 보안 상의 이유로 실제 프로덕션에서는 사용할 때 주의가 필요합니다.
쿠키 설정: 쿠키의 도메인과 경로(Path) 설정을 확인하세요. 도메인이 설정되지 않았거나 경로가 잘못 설정된 경우 쿠키가 저장되지 않을 수 있습니다. 프론트엔드와 백엔드가 다른 도메인에서 서비스되고 있다면 쿠키의 Domain
속성을 적절히 설정해야 합니다.
HTTPS 설정: 프로덕션 환경에서는 Secure
쿠키 옵션과 HTTPS를 사용하는 것이 일반적입니다. 현재 secure: false
로 되어 있는데, 프로덕션 환경에서 HTTPS를 사용한다면 secure: true
로 변경해야 쿠키가 제대로 전달됩니다.
origin
배열에 포함시키고, 서버와 클라이언트 간의 쿠키 공유를 위해 cookie
설정에서 Domain
속성을 올바르게 설정해야 할 수 있습니다.secure
쿠키 옵션을 적극 고려해 보세요.저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
2024. 06. 24. 17:52
네 선생님
기존에는 도메인이 달랐고 탄력적 IP로 바꾼다음에는
프론트: xxx.com
백엔드: api.xxx.com 으로 도메인 맞춰서 작업했습니다.
그럼에도 incredentials만으로는 쿠키전달이 안되서
다른 비슷한 질문과 구글링해보고
클라이언트에서는 api router이용해서 서버함수를 실행하고 서버함수에서 쿠키를 가져와서 전달하면 작동한다는 글을 보고 따라해보니 되더라구요.
그래서 다른 api호출도 다 이런 방식으로 바궈야 401에러가 안날것 같은데 이런 방식으로 진행해도 될지 궁금합니다.
예: 클라이언트에서 /api/user/make 호출 -->
api/user/make/route.ts에서 서버함수 호출 --> 이후 데이터 리턴