현재 풋살 예약 커뮤니티 어플리케이션을 만들고 있으면서 기능들을 하나하나 구현할때마다 블로그에 자세하게 작성하고 있습니다. 전체 소스코드는 깃허브를 통해서 확인해주시길 바랍니다.
https://github.com/kitten-master/FSC_server
GitHub - kitten-master/FSC_server: 풋살 어플리케이션 서버
풋살 어플리케이션 서버. Contribute to kitten-master/FSC_server development by creating an account on GitHub.
github.com
일반적인 로그인은 서버에서 세션을 통해 이루어집니다. 사이트에 접속하면 세션을 서버가 저장하게 되고 이 세션이 만약 기하급수적으로 늘어가게되면 세션을 따로 관리하는 서버를 증설해야할 것 입니다.
Restful API에서는 세션을 저장하는 것을 지향하지 않습니다.
클라이언트에서 로그인 정보가 일치하게 되면 서버에서는 토큰을 발행 해주게됩니다. 이 토큰은 서버에서 설정된 유효시간만큼 유효하며, 유효한 시간안에서 유저와 서버의 데이터 주고받음은 이 토큰을 헤더에 넣은 상태로 사용자를 인증하게 됩니다. 우리는 로그인 API를 만들어봄으로써, 로그인 이후 앱을 사용하기 위해서 필요로한 토큰인증 과정까지 살펴볼예정입니다.
클라이언트와 서버의 규칙
클라이언트
- GET : 조회하다
- POST : 갱신하다
- PUT : 갱신하다
- DELETE : 삭제하다
서버
헤더에서의 규칙(대부분 사람들이 공용으로 사용하는 응답 규칙같은 것이라 보면된다.)
- 201 - POST로 요청이 들어와 서버에서 자원을 생성하는 것에 성공한다면 201 응답을 클라이언트에게 준다.
- 204 - 성공하였지만 응답할 바디가 없는 경우 204로 응답한다.
- 401 - 인증이 허가되지 않은 사용자에 대한 요청일 경우 401로 응답한다.
- 404 - 조회를 하였지만 데이터가 없는 경우 404로 응답한다.
- 409 - 클라이언트에서 서버에 자원 생성을 요청하였을 때 이미 중복된 자원이 있어서 추가할 수 없는 경우 409로 응답한다.
- 503 - 서버의 상태가 과부하 상태이거나 일시적으로 점검일 때 처리할 수 없는 경우 503으로 응답한다.
- 504 - 게이트웨이에 문제가 생겨 시간초과인 경우 504로 응답한다.
- 505 - HTTP 버전에서는 지원불가한 서비스일 경우 505로 응답한다.
바디에서는 JSON 타입으로 요청에 맞는 결과를 클라이언트에 전송시켜준다.
모듈설명
- body-parser - 클라이언트의 요청 응답 body로부터 파라미터를 편리하게 추출한다. express v4.16.0 기준으로 body parser가 빌트인되어서 따로 별도의 설치가 필요없습니다.
- bcrypt-nodejs - 현업에서 많이 사용하고 있는 패스워드 암호화 알고리즘이다.
- jsonwebtoken - json으로 전자 서명을 하며 URL-safe 문자열로 표현한 것이다. 헤더, 페이로드, 서명으로 구성된다. 헤더에는 토큰의 유형을 나타내고 페이로드는 클레임이라고 부르는 이름과 값의 쌍으로 이루어져 있다. 마지막으로 시그니처는 시크릿 키를 포함하여 암호화 되어있다.
1. 클라이언트가 로그인을 요청한다.
2. 서버는 클라이언트의 요청을 확인하여 secret key를 통해 토큰을 발행하여 클라이언트에 전송한다.
3. 로그인 이후 클라이언트가 API를 요청할 때마다 헤더에 토큰을 담아서 보낸다.
4. 서버는 JWT 시그니처를 체크하고 페이로드로부터 사용자 정보를 확인하여 요청에 맞는 데이터를 반환한다.
JWT 사용의 이점
앞서 말했듯이 세션을 따로 서버에서 관리하지 않아도 되는 장점이 있습니다. 또한 별도의 인증 저장소가 필요없으므로 데이터베이스와 중앙 집중식 인증 서버에 의존하지 않아도 된다. 주로 회원 인증하는 부분에서 주로 이용되고 정보교류나 여러가지 방면에서 활용됩니다.
실습환경
DB - MySQL
IDE - Vs code
소스코드
MVC 패턴으로 코드를 작성해보았습니다. 많이 미숙하지만 여러가지를 참고하여 작성하였습니다.
https://kangeee.tistory.com/235?category=1005552
[NodeJS] Express의 모든 정리
npm init 먼저 프로젝트를 생성할 빈폴더에서 시작하여 터미널에서 npm init을 해줍니다. npm init은 프로젝트 초기 생성시 기본적으로 설명이나 버전 등 프로젝트 폴더의 설명을 적는 단계라 보시면
kangeee.tistory.com
우선 프로젝트의 초기생성법을 정리해두었습니다. 모든 과정을 안다고 가정하고 작성하도록 하겠습니다.
회원가입의 로직
- 클라이언트가 POST 요청으로 회원가입 폼에 작성된 데이터를 서버로 보낸다.
- 서버는 클라이언트에서 받은 user의 데이터를 라우터에서 컨트롤러로 보낸다. 컨트롤러에 보내기전에 데이터의 유효성을 먼저확인한다. 만약 데이터가 유효하지 않을경우 에러 메시지를 보낸다.
- id - 최소3글자~15글자 이하
- password - 최소 6글자이상
- 이메일 - 우선 1글자 이상으로 설정
- 유저닉네임 - 최소3글자~15글자 이하
- 컨트롤러에서 user 모델에 저장해서 모델에서 데이터베이스에 저장하고 결과 값을 컨트롤러로 리턴한다.
- 컨트롤러에서 결과를 받은 값이 성공적으로 데이터베이스에 저장되었으면 성공을 리턴, 중복된 아이디가 있는 경우 실패를 리턴한다.
회원가입 유저 데이터베이스 테이블 현황
id | password | username | |
VARCHAR(45) | VARCHAR(200) | VARCHAR(45) | VARCHAR(45) |
app.js
const express = require('express');
const app = express();
const cors=require('cors');
const bodyParser = require('body-parser');
const registerRouter = require('./routes/user');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use(cors());
app.use('/auth',registerRouter);
app.listen(3000, function () {
console.log("start!! express server on port 3000")
});
module.exports = app;
db.js
const mysql = require('mysql');
const con = mysql.createConnection({
host:'localhost',
user:'root',
password:'암호설정',
port:3306,
database:'데이터베이스 스키마 이름',
multipleStatements: true
});
con.connect((err) => {
if (err) throw err;
else console.log("connection success!!");
})
module.exports = {
con
}
routes/user.js
const express = require('express');
const router = express.Router();
const controller = require('../controllers/usercontroller');
const {validateRegister} = require('../middleware/users');
router.post('/register',validateRegister,controller.insertUserProcess);
module.exports = router;
middleware/users.js
const jwt= require('jsonwebtoken');
module.exports = {
validateRegister: (req, res, next) => {
//username min length 3 max length 15
//password min 6chars
if(!req.body.id || req.body.id.length < 3 || req.body.id.length>15){
return res.status(400).send({
message: "input your id or 3~15 write id",
});
}
if(!req.body.username || req.body.username.length < 3 || req.body.username.length>15){
return res.status(400).send({
message: "input your username or 3~15 write username",
});
}
if(!req.body.password || req.body.password.length < 6){
return res.status(400).send({
message: "input your password or 6upper write password",
});
}
if(!req.body.email || req.body.email.length < 1){
return res.status(400).send({
message : "input your email or 1upper email",
});
}
next();
}
}
controllers/usercontroller.js
const User = require('../models/usermodel');
exports.insertUserProcess = (req,res) => {
let item={
'id':req.body.id,
'username':req.body.username,
'password':req.body.password,
'email':req.body.email
};
User.insertData(item,(result)=>{
if(result){
if(result.affectedRows===1){
res.status(201).send({
message:'create ID success!'
});
}
else{
res.status(409).send({
message:'signup failed! because duplicate error, use a different ID'
});
}
}
})
}
models/usermodel.js
const User = require('../models/usermodel');
exports.insertUserProcess = (req,res) => {
let item={
'id':req.body.id,
'username':req.body.username,
'password':req.body.password,
'email':req.body.email
};
User.insertData(item,(result)=>{
if(result){
if(result.affectedRows===1){
res.status(201).send({
message:'create ID success!'
});
}
else{
res.status(409).send({
message:'signup failed! because duplicate error, use a different ID'
});
}
}
})
}
Comment
post 요청 - /auth/register
유저 데이터베이스 테이블
id varchar(45)
password | varchar(200) |
varchar(45) | |
username | varchar(45) |
POST 요청 JSON 형식
{
"id":"아이디",
"username":"유저닉네임",
"password":"비밀번호",
"email":"이메일"
}
회원가입 예외케이스
- id - 최소3글자~15글자 이하
- password - 최소 6글자이상
- 이메일 - 우선 1글자 이상으로 설정
- 유저닉네임 - 최소3글자~15글자 이하
'Programming > nodejs' 카테고리의 다른 글
[NodeJs] JWT(Json web Token) 로그인 Restful API 만들기 - 로그인 검증 (0) | 2022.01.18 |
---|---|
[NodeJs] JWT(Json web Token) 로그인 Restful API 만들기 - 로그인편 (0) | 2022.01.17 |
[NodeJS] Express의 모든 정리 (0) | 2022.01.14 |
[NodeJS] MySQL 다중 쿼리문 - Multiple Statements (0) | 2021.11.03 |
[NodeJS] 넷폴릭스 크롤링 (0) | 2021.10.03 |