API 요청에 대해 사용 가능한 사용자인지 확인하는 절차
key - value 쌍으로 구성된, 사용자에 컴퓨터에 저장되는 작은 기록 정보 파일
일정 시간동안 같은 사용자로부터 들어오는 일련의 요구를 하나의 상태로 보고, 그 상태를 일정하게 유지시키는 기술
쿠키는 클라이언트 로컬에 저장되기 때문에 정보가 변질되거나 스나이핑 당할 수 있음
세션은 서버에서 세션 저장소를 사용하므로 추가적인 저장공간이 필요. 세션 저장소에 장애가 발생하면 인증에 문제
Json Web Token
클레임 토큰 기반 인증방식.
클라이언트의 세션 상태를 저장하는 것이 아니라 필요한 정보를 토큰 body에 저장해서 클라이언트가 가지고 이를 증명서처럼 사용
Header.Payload.Verify_Signature
Header : 서명에 사용된 알고리즘의 정보
Payload : 토큰의 정보를 작성, 클레임이라고 표현- 클라이언트에 대한 정보가 담겨 있음.
Signature : 토큰이 중간에 변경되지 않았다는 것을 검증 - header에서 지정한 알고리즘과 secret key로 header와 payload를 담는다.
npm install jsonwebtoken
module.exports = {
secretKey: 'SecretKeySoptSeRvER',
options: {
algorithm: "HS256",
expiresIn: "1h",
issuer: "kgy",
},
refreshOptions: {
algorithm: "HS256",
expiresIn: "7d",
issuer: "kgy",
},
}
const jwt = require('jsonwebtoken');
const { secretKey, options, refreshOptions } = require('../config/secretKey');
const TOKEN_EXPIRED = -3;
const TOKEN_INVALID = -2;
module.exports = {
// jwt 생성
sign: async (user) => {
const payload = {
id: user.id,
name: user.userName
};
const result = {
accessToken: jwt.sign(payload, secretKey, options),
refreshToken: jwt.sign(payload, secretKey, refreshOptions),
};
return result;
},
// jwt 식별
verify: async (token) => {
let decoded;
try {
decoded = jwt.verify(token, secretKey);
} catch (err) {
if (err.message === 'jwt expired') {
console.log('expired token');
return TOKEN_EXPIRED;
} else if (err.message === 'invalid token') {
console.log('invalid token');
console.log(TOKEN_INVALID);
return TOKEN_INVALID;
} else {
console.log("invalid token");
return TOKEN_INVALID;
}
}
return decoded;
}
}
signin : async (req, res) => {
const { email, password } = req.body; // 1. req.body에서 데이터 가져오기
//2. request data 확인하기, email, password, userName data가 없다면 NullValue 반환
if (!email || !password) {
console.log('필요한 값이 없습니다!');
return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, responseMessage.NULL_VALUE));
}
try{
//3. 존재하는 아이디인지 확인하기. 존재하지 않는 아이디면 NO USER 반환
const user = await User.findOne({
where : {
email : email
},
});
//4. 비밀번호 확인하기 - 로그인할 email의 salt를 DB에서 가져와서 사용자가 request로 보낸 password와 암호화를 한후 디비에 저장되어있는 password와 일치하면 true
// 일치하지 않으면 Miss Match password 반환
const {id, userName, salt, password : hashedPassword} = user;
const inputPassword = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('base64');
if (inputPassword != hashedPassword) {
console.log('비밀번호가 일치하지 않습니다.');
return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.OK, responseMessage.MISS_MATCH_PW));
}
const {accessToken, refreshToken} = await jwt.sign(user);
//5. status: 200 ,message: SIGN_IN_SUCCESS, data: id, email, userName 반환
return res.status(statusCode.OK).send(util.success(statusCode.OK, responseMessage.SIGN_IN_SUCCESS, {accessToken, refreshToken}));
} catch (error) {
console.error(error);
return res.status(statusCode.INTERNAL_SERVER_ERROR).send(util.fail(statusCode.INTERNAL_SERVER_ERROR, responseMessage.SIGN_IN_FAIL));
}
},
const express = require('express');
const router = express.Router();
const ut = require('../modules/util');
const sc = require('../modules/statusCode');
const rm = require('../modules/responseMessage');
const jwt = require('../modules/jwt');
const TOKEN_EXPIRED = -3
const TOKEN_INVALID = -2
const authUtil = {
checkToken : async (req, res, next) => {
const token = req.headers.jwt;
if (!token) {
return res.json(ut.fail(sc.BAD_REQUEST, rm.EMPTY_TOKEN));
}
const user = await jwt.verify(token);
console.log('hello', user);
if (user === TOKEN_EXPIRED) {
return res.status(sc.UNAUTHORIZED).send(ut.fail(sc.UNAUTHORIZED, rm.EXPIRED_TOKEN));
}
if (user === TOKEN_INVALID) {
return res.status(sc.UNAUTHORIZED).send(ut.fail(sc.UNAUTHORIZED, rm.INVALID_TOKEN));
}
if (user.id === undefined) {
return res.status(sc.UNAUTHORIZED).send(ut.fail(sc.UNAUTHORIZED, rm.INVALID_TOKEN));
}
req.decoded = user;
next();
},
}
module.exports = authUtil;
: REpresentational State Transfer API
구성
자원 RESOURCE - URI
행위 : - HTTP METHOD
표현(Representations)
리소스명은 동사보다는 명사
GET/members/show
x
GET/hahaha
x
GET/members
o
GET/sopt/server.png
x
GET/sopt/server/png
o
document는 하나의 객체(문서), collection은 그 객체들의 집합
http://sopt.org/parts/server/users/2
API: Application Programming Interface
클라이언트가 서버에서 만든 API 를 사용하기 위해 참고하는 사용 설명서
web, server의 서버가 다르면 오류
npm install cors
-app.js에서
const cors = require('cors');
app.use(cors());