YS's develop story
(RP2기 5주차 과제 - part 2) JWT를 사용하여 회원용 API 만들기 (Node js) 본문
2번째 과제 : JWT를 사용하여 회원용 API 만들기
로그인 유지 방식 3가지(수업 내용 정리)
1. 쿠키, 세션
“자유이용권을 주는 것.”
맨 처음 클라이언트가 로그인을 할 경우, 서버에서 자유이용권 (토큰, 세션 ID)를 발급한다.
이후에 클라이언트가 회원용 API를 호출할 경우 http 헤더에 이 세션 ID가 담겨서 자유롭게 사용할 수 있다.
세션이란 서버 입장에서의 스토리지 이름이다.
쿠키라는 것은 클라이언트 스토리지 이름이다.
장점: 구현이 간단하다.
단점: 세션 ID가 노출되면 보안에 매우 취약하다.
2.OAuth
“Big-3 티켓을 주는 것” → 특정 행위에 대해서만 권한을 주는 것
이 역시 로그인에 성공하면 서버에서 토큰을 보낸다.
단, 그전에 퍼미션 리스트도 함께 보낸다. 즉, 허용된 권한만 사용할 수 있게 하는 로그인 유지 방식이다.”
“카카오톡 게임을 할 때 어떤 정보를 제공할지 체크하는 것이 OAuth 방식 로그인의 대표적인 예시이다.”
리프레시 토큰: 한 달가량 유효 → 리프레시 토큰의 사용을 최소화하여 보안성을 높인다.
액세스 토큰: 몇 분 단위로 갱신 → 리프레시 토큰이 있어야 액세스 토큰을 발급받을 수 있다.
이 액세스 토큰으로 회원용 API에 접근할 수 있다.
장점: 보안성이 우수
단점: 과정이 복잡한 만큼 리소스가 많이 필요
3.JWT (Json Web Token)
“매번 놀이기구를 탈 때마다 권한을 검사하는 것”
“소프트 스퀘어드에서 주로 사용하는 방식”
클라이언트가 ID, PWD를 매번 서버에 보낸다. → 서버는 이 정보를 64진법 인코딩하여 토큰으로 만들어
클라이언트에 보낸다.
“인코딩 된 정보는 JWT의 페이로드에 해당하는 부분이다. 헤더에는 인코딩 방식 등의 메타데이터가 담겨있다.”
시그니처: 헤더와 페이로드를 암호화 한 값.
-
ID, PWD 검증 → 유효한 토큰인지 시그니처 비교
장점: 리소스가 적게 필요하다.
단점: 보안에 취약하다. → HTTPS이 꼭 요구됨
클라이언트 입장에서 어떻게 로그인을 유지시킬까?
“모든 플랫폼 (AOS, iOS, Web)은 각자의 로컬 스토리지가 있다!”
→ 로그인 토큰을 로컬 스토리에 저장한다.
자동 로그인을 할 경우 이 토큰을 서버에 보내는 방식으로 토큰을 유지한다.
API 설계 부분
회원가입 API
exports.signUp = async function (req, res) {
const {
userEmail, userPassword,checkUserPassword,userName
} = req.body;
//if (!isEmail(userEmail))
// return res.json({isSuccess: false, code: 300, message: "이메일 형식이 올바르지 않습니다."});
if (!userEmail) return res.json({isSuccess: false, code: 301, message: "이메일을 입력해주세요."});
if (userEmail.length > 30) return res.json({
isSuccess: false,
code: 302,
message: "이메일은 30자리 미만으로 입력해주세요."
});
if (!regexEmail.test(userEmail)) return res.json({isSuccess: false, code: 303, message: "이메일을 형식을 정확하게 입력해주세요."});
if (!userPassword) return res.json({isSuccess: false, code: 304, message: "비밀번호를 입력 해주세요."});
if (userPassword.length < 8 || userPassword.length > 20) return res.json({
isSuccess: false,
code: 305,
message: "비밀번호는 8~20자리로 입력해주세요."
});
if (!checkUserPassword) return res.json({isSuccess: false, code: 306, message: "비밀번호 확인을 입력해 주세요."});
if (userPassword != checkUserPassword ) return res.json({isSuccess: false, code: 307, message: "비밀번호와 비밀번호 확인이 다릅니다."});
if (!userName) return res.json({isSuccess: false, code: 308, message: "닉네임을 입력 해주세요."});
if (userName.length > 10) return res.json({
isSuccess: false,
code: 309,
message: "닉네임은 10자리 이하로 입력해주세요."
});
if (!/^([a-zA-Z0-9ㄱ-ㅎ|ㅏ-ㅣ|가-힣]).{1,10}$/.test(userName))
return res.json({
isSuccess: false,
code: 310,
message: "닉네임은 한글, 영문, 숫자만 입력가능하고 2자 이상이어야 합니다.",
});
try {
// 이메일 중복 확인
const emailRows = await userDao.userEmailCheck(userEmail);
if (emailRows.length > 0) {
return res.json({
isSuccess: false,
code: 311,
message: "중복된 이메일입니다."
});
}
// 닉네임 중복 확인
const nicknameRows = await userDao.userNicknameCheck(userName);
if (nicknameRows.length > 0) {
return res.json({
isSuccess: false,
code: 312,
message: "중복된 닉네임입니다."
});
}
// TRANSACTION : advanced
// await connection.beginTransaction(); // START TRANSACTION
const hashedPassword = await crypto.createHash('sha512').update(userPassword).digest('hex');
const insertUserInfoParams = [userEmail, hashedPassword, userName];
const insertUserRows = await userDao.insertUserInfo(insertUserInfoParams);
// await connection.commit(); // COMMIT
// connection.release();
return res.json({
isSuccess: true,
code: 200,
message: "회원가입 성공"
});
} catch (err) {
// await connection.rollback(); // ROLLBACK
// connection.release();
logger.error(`App - SignUp Query error\n: ${err.message}`);
return res.status(500).send(`Error: ${err.message}`);
}
};
사용자로부터 입력받는 비밀번호는 해시함수를 통해서 DB에 알 수 없게 암호 형식으로 저장해야 합니다.
사용자로부터 입력받는 이메일, 닉네임 등등은
개발자가 원하는 값만 입력될 수 있도록 정규식을 사용해야 합니다.
JS 정규식 모음 ) 전화번호, 닉네임, URL, 휴대폰 번호, 이메일 체크 정규식
JS 정규식 모음 ) 전화번호, 닉네임, URL, 휴대폰 번호,이메일 체크 정규식
DATA 정규식 0000-00-00 if(!/^(19|20)\d{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[0-1])$/.test(reservationDate)) return res.json({isSuccess: false, code: 301, message: "올바른 날짜가 아닙니다. 유효한 날..
yusang.tistory.com
JWT 토큰 생성
로그인 페이지 API
userController.js
userRoute.js
userDao.js
위의 로그인 페이지를 통해 로그인을 하게 되면 아래와 같이 토큰을 생성합니다.
이 토큰은 userController.js에서 표시한 노란색 네모 박스의 정보를 모두 가지고 있습니다.
실제로 그런지 아래 사이트에서 확인해 봅시다.
JWT.IO
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
jwt.io
위의 결과와 같이 이는 정보가 인코딩 된 형식이므로
이 토큰에는 암호와 같은 중요한 정보가 들어가서는 절대 안 됩니다!
발급받은 이 토큰을 검증하기 위해서는 아래와 같이 Headers에 토큰 값을 넣어 주면 됩니다.
이 토큰을 이용하여 로그인 중인 사용자만이 사용할 수 있는 사용자 API를 생성할 수 있습니다.
예를 들면 아래와 같습니다.
토큰으로부터 userId값을 받아와서 사용자 개인정보를 볼 수 있는 API를 설계할 수 있는 것입니다.
userController.js
userDao.js
토큰에는 아래와 같이 userId, userEmail, userName, userLatitue, userHardness가 저장되어 있습니다.
Postman에서의 실행 결과.
JWT 토큰을 활용하여 리뷰의 수정권한 체크
사용자가 작성한 리뷰를 삭제하거나 수정하려면 그 사용자에게 해당 리뷰를 수정할 수 있는
권한이 있는지 확인을 해야합니다.
내가 작성한 리뷰를 다른사람이 수정하거나 삭제하면 안 되기 때문이죠.
JWT토큰을 활용하여서 특정행동에 권한을 확인할 수 있습니다.
pathvariable로 reviewId를 넘겨받은 후
그 리뷰에 저장되어 있는 userId와 토큰에 저장된 userId가 같은지 확인을 진행합니다.
같다면 그 유저가 작성한 리뷰가 맞기 때문에 수정할 수 있고
그렇지 않다면 그 유저가 작성한 리뷰가 아니기 때문에 권한을 부여하지 않습니다.
userController.js
userDao.js
이렇게 JWT를 사용하여 사용자 전용 API를 여러 개 설계하는 것이 이번 주 과제의 목표입니다!!
저번 주 과제에 이어서 추가한 api를 api명세서에 추가하여 업데이트하는 중입니다!
docs.google.com/spreadsheets/d/1Zw9Q9GtI5gqAeZHfsJmILvcVwINKMHejNJ7pWRJeDVY/edit?usp=sharing
RP2기 api 명세서
개요 Index,Method,URI,Description,명세서,서버 반영 여부 1,GET,/main,메인조회,OK,Y 2,GET,/café,카페검색,OK,Y 3,GET,/cafe/:cafeid,카페상세조회,OK,Y 4,GET,/cafe/:cafeid/review,카페리뷰상세조회,OK,Y 5,POST,/cafe/:cafeid/review
docs.google.com
그럼 이번 주 과제의 기록은 여기까지!!
'기타 > 라이징프로그래머 2기' 카테고리의 다른 글
(RP2기 6주차 과제 ) AWS EC2에서 node.js 배포 하기 (0) | 2021.02.06 |
---|---|
포트와 프로토콜 내용 정리 (0) | 2021.02.04 |
(RP2기 5주차 과제 - part 1) AWS RDS 생성하고 외부 접속 하기. (0) | 2021.02.02 |
(RP2기 4주차 과제 - part 3) Node js 를 활용하여 서비스에 필요한 rest api 설계 및 구현 (2) | 2021.02.01 |
(RP2기 4주차 과제 - part 2) Node js 를 활용하여 서비스에 필요한 rest api 설계 및 구현 (0) | 2021.02.01 |