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, 휴대폰 번호, 이메일 체크 정규식
JWT 토큰 생성
로그인 페이지 API
userController.js
userRoute.js
userDao.js
위의 로그인 페이지를 통해 로그인을 하게 되면 아래와 같이 토큰을 생성합니다.
이 토큰은 userController.js에서 표시한 노란색 네모 박스의 정보를 모두 가지고 있습니다.
실제로 그런지 아래 사이트에서 확인해 봅시다.
위의 결과와 같이 이는 정보가 인코딩 된 형식이므로
이 토큰에는 암호와 같은 중요한 정보가 들어가서는 절대 안 됩니다!
발급받은 이 토큰을 검증하기 위해서는 아래와 같이 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
그럼 이번 주 과제의 기록은 여기까지!!
'기타 > 라이징프로그래머 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 |