nodejs api 인증 예제 ( JWT, sequelize, express )
백엔드 개발에서 가장 중요한 API 인증 예제입니다.
nodejs 언어를 사용하고, API 는 express 를 ORM (object relational mapping) 는 sequelize 를 사용했습니다.
api 인증을 위해서는 JWT (json web token) 를 사용했습니다.
회원가입, 로그인, 내정보보기의 3가지 API 를 구현했습니다.
1. 예제 소스코드 다운로드
github.com/vipick/nodejs-auth-example
2. 소스코드 주요 폴더 및 파일
app/config/config.js | 개발 환경 및 운영서버에서 DB 엑세스 구별 |
app/controllers/auth.controllers.js | 인증 컨트롤러 |
app/models/index.js | DB 엑세스 및 사용하는 모델 초기화 코드 |
app/models/user.model.js | user 모델 및 관계를 정의 : users 테이블 생성 코드 |
app/routes/index.js | 라우터 |
app/routes/verifyJwtToken.js | API 인증을 위한 미들웨어 코드 |
.env | 외부에 노출되면 안되는 key 값을 저장합니다. (예: JWT secret, DB 아이디, 패스워드, ip주소 등) 보통 git으로 관리하지 않습니다. (.gitignore) 운영 서버에서는 .env-example 에서 이름 명을 .env로 변경하고 key 값을 작성합니다. |
.gitignore | git 으로 관리하지 않는 파일/폴더를 지정 |
app.js | 메인 |
server.js | app.js 를 실행 |
package.json | 외부 프로그램 버전 관리 |
실제 코드 작성이 많이 필요한 곳은 라우터, 컨트롤러, 모델 이렇게 3군데 입니다.
나머지 코드는 세팅 부분으로 많은 수정이 없습니다.
2-1) 라우터
- routes 폴더의 index.js 파일에서 각각의 api 를 정의합니다.
- 내 정보 api 미들웨어에서 인증 토큰 값을 검증합니다.
- 인증 토큰 값은 로그인 시 얻게 되고, 백엔드 인증 api를 요청할 때 토큰 값을 포함시켜서 보내면 인증이 필요한 백엔드 기능을 사용할 수 있습니다.
2-2) 컨트롤러(Controller)
- 회원가입 시 bcrypt 함수로 암호화를 합니다.
- 로그인 시 회원정보 가(아이디, 패스워드) 일치 하면 jwt secret key 값을 활용해서 token 값을 생성 합니다. 86400 숫자는 24시간 만 유효하다는 것 입니다. 이 시간이 지나면 재로그인 필요합니다.
- User 모델을 사용해서 users DB 테이블에서 회원가입(create), 조회(findOne)를 진행했습니다.
- 모델에 대한 추가적인 공부 구글에서 sequelize 키워드를 검색하면 됩니다.
const { User } = require("../models");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
/**
* 회원가입
*/
exports.signup = async (req, res) => {
try {
const user = await User.create({
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
type: req.body.type,
});
if (user) {
return res.status(201).send("회원가입 성공!");
}
} catch (err) {
return res.status(500).send("회원가입 실패!" + err);
}
};
/**
* 로그인
*/
exports.signin = async (req, res) => {
let user = null;
try {
user = await User.findOne({
where: {
email: req.body.email,
},
});
if (!user) {
return res.status(404).send("User Not Found.");
}
} catch (err) {
return res.status(500).send("Error -> " + err);
}
const passwordIsValid = bcrypt.compareSync(req.body.password, user.password);
if (!passwordIsValid) {
return res.status(401).send({
auth: false,
accessToken: null,
reason: "Invalid Password!",
});
}
const token = jwt.sign(
{
id: user.id,
},
process.env.JWT_SECRET,
{
expiresIn: 86400, // expires in 24 hours
}
);
return res.status(200).send({
auth: true,
accessToken: token,
});
};
/**
* 내 정보 보기
*/
exports.me = async (req, res) => {
try {
const user = await User.findOne({
attributes: ["type"],
where: {
id: req.userId,
},
});
if (user) {
return res.status(200).json({
description: "회원정보 보기",
content: user,
});
}
} catch (err) {
return res.status(500).send("Error -> " + err);
}
};