CH3 개인과제 일부 수정 및 미들웨어 구현으로 필수/도전 과제는 완료되었다. 분리할 부분이 더 보였지만 제출 시간의 한계로... 거기까진 못하고 제출했다. 😰😰 구현한 미들웨어에 대해 짤막하게 적어보겠다.
그리고 마지막으로 서버 포트 관련하여 정리하고 글을 마치겠다.
로그인 시 헤더에 반환된 토큰을 기준으로 JWT 인증이 필요한 라우트에서 request.header에 authorization이 있는지 확인 후
검증한다.
토큰이 없을 경우, Bearer 형식이 아닌경우, 페이로드에 담긴 유저 정보가 없는 토큰일 경우에는 에러를 발생시킨다.
export default async function (req, res, next) {
try {
const { authorization } = req.headers; // 헤더에서 토큰 정보 추출
if (!authorization)
// 토큰이 없을 시 에러
throw new CustomErr("요청한 사용자의 토큰이 없습니다.", 404);
const [tokenType, token] = authorization.split(" "); // 토큰 형식과 데이터 분리
if (tokenType !== "Bearer")
// 베어러 타입이 아닐경우 에러
throw new CustomErr("토큰 타입이 Bearer 형식이 아닙니다.", 400);
const decodedToken = jwt.verify(token, SECRET_CODE); // 토큰 디코딩
const userId = decodedToken.userId; // 디코딩한 토큰의 페이로드 내 유저ID 삽입
const user = await prisma.users.findFirst({
where: { userId: userId },
});
// 해당하는 유저가 없을 시 에러
if (!user) throw new CustomErr("토큰 사용자가 존재하지 않습니다.", 404);
req.user = user; // request에 user 객체 설정
next(); // 다음 미들웨어로 전달
} catch (err) {
return res.status(400).json({ message: err.message });
}
}
특정 라우터에서 중복된 부분이 있어 미들웨어로 만들어 추가해주었다.
인증 미들웨어를 거친 후 user 객체와 캐릭터 번호로 character 테이블에서 조회를 하고 있을 경우 character 객체로 다음 미들웨어로 전달해주고 아니면 에러를 반환.
export default async function (req, _, next) {
try {
// 인증 미들웨어에서 생성한 user와 URL 매개변수에서 추출
const {
user: { userNo },
params: { characterNo },
} = req;
const character = await prisma.characters.findFirst({
where: { characterNo: +characterNo }, // characterNo 와 일치한 데이터 요청
});
if (!character)
throw new CustomErr("캐릭터가 정보가 존재하지 않습니다.", 404); // 캐릭터 객체가 없을 시 에러
if (character.userNo !== userNo)
throw new CustomErr("캐릭터 접근 권한이 없습니다.", 401); // 캐릭터 소유권자와 토큰 인증자가 다를 시 에러
req.character = character; // request에 캐릭터 객체 설정
next();
} catch (err) {
return res.status(400).json({ message: err.message });
}
}
커스텀 에러 클래스를 생성하여 에러를 throw할 때 에러 정보와
status code를 받아 처리하는 미들웨어를 만들었다.
try-catch 구문을 통해 에러 부분을 customErr로 throw 해주면, catch는 에러 미들웨어로 정보를 넘긴다.
에러 미들웨어에서는 해당 에러 내용을 처리한다.
에러로그 미들웨어는 에러가 생겼을 경우 로그를 터미널에 출력한다.
constructor(message, statusCode) {
super(message); // Error 클래스의 message 속성 설정
this.statusCode = statusCode; // 추가적인 statusCode 속성 설정
}
export default function (err, req, res, next) {
// statusCode 가 전달되지 않은 경우 지정 외 에러이므로 500 할당
const statusCode = err.statusCode || 500;
// 서버 에러 출력
console.error(err);
if (statusCode === 500)
res.status(500).json({ errorMessage: "서버 내부 에러가 발생했습니다." });
// 클라이언트에게 에러 메시지를 전달
res.status(statusCode).json({
errorMessage: err.message,
statusCode: statusCode,
});
}
// winston 설정에서 로그 레벨을 error로 설정
const logger = winston.createLogger({
level: "error", // error 로그만 출력
format: winston.format.json(),
transports: [
new winston.transports.Console({
level: "error",
}),
],
});
export default function (req, res, next) {
const start = new Date().getTime();
res.on("finish", () => {
// 응답속도 계산
const duration = new Date().getTime() - start;
if (res.statusCode >= 400) {
// 오류 상태 코드일 경우 error 레벨로 로그
logger.error(
`Method: ${req.method}, URL: ${req.url}, Status: ${res.statusCode}, Duration: ${duration}ms`
);
}
});
next();
}
과제를 제출하기 위하여 EC2에 pm2로 서버를 올리고 도메인 연결 후 서버에 접속하는데 포트번호를 치는 것이 너무 귀찮아서
없애기로 했다.
방법은 일반적으로 포트포워딩이 있고 리눅스에서 iptables을 통해 변경할 수 있다고 한다.
허나, 웹 기술 상의 다양한 보안 공격에 대해 탄력적으로 대응하기 어렵다는 의견들이 있어서 프록시 서버를 구축하고
프록시 패스 ( 80으로 들어온 요청을 내가 원하는 포트로 보내줌 )를 설정하기로 했다.
sudo apt upgrade
아파치서버를 다운받기 위하여 apt를 최신버전으로 다운받는다.
sudo apt-get install apache2
위 명령어를 이용하여 관리자 권한으로 apache2 를 다운받아준다.
sudo vi /etc/apache2/sites-avaliable/000-default.conf
해당 경로에 있는 conf파일을 vi를 이용하여 열어준다.
<VirtualHost *:80>
ServerName example.com
ServerAdmin admin@email.com
DocumentRoot /var/www/html
ProxyRequests Off
ProxyPreserveHost On
ErrorLog ${APACHE_LOG_DIR}/error.log
ProxyPass / http://localhost:원하는 포트/
ProxyPassReverse / http://localhost:원하는 포트/
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
</VirtualHost>
안에 있는 내용을 모두 지우고 위의 내용으로 복붙한다.
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_html
sudo service apache2 restart
마지막으로 아파치 활성화 명령어 및 재부팅 명령어를 입력하고 접속시도하면 된다!
출처
[Web] 9편 - Ubuntu 20.04에서 Apache2를 사용하여 3000포트를 포트 바꿔서 배포하기
AWS 의 EC2 로 우분투 서버 구축하였습니다. 포트 포워딩에 대해서.
단, 리눅스 내 방화벽 설정따윈 하지 않은 나같은 코린이들의 경우인거고 리눅스 내에 방화벽 설정을 켜놓았다면
해당 포트에 대하여 허용해주어야 한다.
또 EC2 인스턴스를 사용중이라면, 인바운드 규칙에 지정한 포트를 추가해주어야 된다는 점~😁