셀프 레퍼런스
https://flreauniverse.tistory.com/26 (세션과 토큰)
개요
- 유저 스키마와 모델 생성하기
- 유저 crud 구현하기
- 로그인 api를 연결하고 토큰 발급하기
- 토큰 검증하기
- api 테스트하기
- (번외) 비밀번호 암호화
유저 스키마와 모델 생성하기
스키마와 모델 생성은 지난 시간에 해본 적 있습니다.
실력을 더욱 키우고 싶다면 아래 코드를 보지 말고 한번 짜보는것도 좋은 방법입니다.
유저에 필요한 값은 생각보다 간단합니다.
이 두가지 값을 코드로 옮겨보겠습니다.
model 폴더 아래에 user.js 파일을 만든 뒤 아래 코드를 작성해주세요.
import mongoose from "mongoose";
const userSchema = new mongoose.Schema({
username: { type : String, required: true, unique: true },
password: { type : String, required: true },
},
{
timestamps: true,
});
export default mongoose.model('User', userSchema);
username에 unique라는 속성을 넣었기 때문에, 이미 저장된 아이디로는 유저 데이터를 생성할 수 없게 되었습니다.
유저 CRUD 생성하기
라우터 파일을 하나 새로 만들겠습니다.
router 폴더 아래에 user.js 파일을 생성해주세요.
import express from 'express';
import User from '../model/user.js'
const userRouter = express.Router();
userRouter.post("/", async (req, res) => {
const data = req.body;
console.log(data);
const username = data.username;
const password = data.password;
const user = new User({
username: username,
password: password,
})
await user.save();
res.send("데이터가 생성되었습니다.");
});
userRouter.get("/", async (req, res) => {
const data = await User.find();
res.send(data);
});
userRouter.get("/:id", async (req, res) => {
const data = await User.findById(req.params.id);
res.send(data);
});
userRouter.patch("/:id", async (req, res) => {
const data = await User.findByIdAndUpdate(req.params.id, req.body);
res.send(data);
});
userRouter.delete("/:id", async (req, res) => {
const data = await User.findByIdAndDelete(req.params.id);
res.send(data);
});
export default userRouter;
저번 postRouter를 복붙한 후, 일부 내용만 수정했습니다.
잊지 말고 index.js 파일에도 라우터를 추가해주세요.
import userRouter from './router/user.js';
...
app.use("/user", userRouter);
...
로그인 api를 연결하고 토큰 발급하기
로그인 api는 POST /login URL을 사용합니다.
router 폴더 아래에 auth.js 파일을 만들어주세요.
yarn add jsontokenweb
import express from 'express';
import jwt from "jsonwebtoken";
import User from '../model/user.js';
const authRouter = express.Router();
authRouter.post("/login", async (req, res) => {
const key = "1234qwer";
const data = req.data;
const username = data.username;
const password = data.password;
const user = await User.findOne({ username: username });
if (!user) {
res.send("사용자를 찾을 수 없습니다.")
}
if (user.password !== password) {
res.send("비밀번호가 틀립니다.");
}
const token = jwt.sign(
{
type: "JWT",
id: user._id,
username: username,
},
key,
{
expiresIn: "30m", // 토큰의 유효 기간입니다. 원하는대로 조절하면 됩니다.
},
);
res.send(token);
})
export default authRouter;
nodejs 라이브러리인 jsonwebtoken을 사용합니다.
request로 username과 password를 받아와서 이를 Key로 암호화 한 뒤 돌려보내는 jwt의 함수 sign을 사용합니다.
sign은 인자 세개로, 토큰의 내용, 암호화 키, 토큰의 옵션을 받습니다.
클라이언트에선 받은 토큰을 헤더에 등록하여 사용하면 됩니다.
암호화 키는 환경변수로 분리해줍시다.
TOKEN_SECRET=1234qwer
.env 파일에 추가해줍니다.
./src/router/auth.js
...
const key = process.env.TOKEN_SECRET;
...
라우터에서도 수정해주면 됩니다.
마지막으로 index.js 파일에도 추가해줍니다.
import authRouter from './router/auth.js';
...
app.use("/auth", authRouter);
토큰 검증하기
클라이언트가 토큰을 쿠키에 등록해 서버에 요청을 보냈을 때, 토큰이 유효한지 검증하는 미들웨어를 작성하겠습니다.
src 폴더 아래에 middleware 폴더를 만들고, 그 안에 다시 auth.js 파일을 만들어주세요.
import jwt from 'jsonwebtoken';
const verifyToken = (req, res, next) => {
const token = req.headers.authorization;
try {
const user = jwt.verify(token, process.env.TOKEN_SECRET);
req.user = user;
return next();
} catch (err) {
return res.send("올바르지 못한 요청입니다.");
}
}
export default verifyToken;
이제 이 미들웨어를 사용해 보겠습니다.
유저 정보를 조회할 때 조건이 있습니다.
1. 로그인이 되어있어야 하고,
2. 본인의 정보여야 합니다.
// ./src/router/user.js
...
userRouter.get("/:id", verifyToken, async (req, res) => {
if (req.user.id !== req.params.id) {
res.send("권한이 없습니다.");
}
const data = await User.findById(req.params.id);
res.send(data);
});
...
따라서 위와 같이 코드를 짤 수 있습니다.
api 테스트하기
사용자 생성-토큰 발급-사용자 정보 조회(성공/실패)까지 api테스트를 해보겠습니다.
가장 먼저, POST localhost:8000/user 요청입니다.
사용자 생성이 제대로 된 걸 확인 후, POST localhost:8000/auth/login 테스트를 진행합니다.
응답으로 받은 문자열을 Headers에 authorization으로 등록합니다.
이제 GET localhost:8000/user/:id에 로그인한 본인이 아닌 다른 정보를 요청하면 다음과 같은 응답을 얻습니다.
올바를 경우, 사용자의 정보를 받아올 수 있습니다.
'코딩 > Express' 카테고리의 다른 글
[express] Schema와 Model을 생성하고 데이터 저장하기 (0) | 2023.07.08 |
---|---|
[express] 데이터베이스에 연결하기 (0) | 2022.03.30 |
[express] 필요한 api 라우팅하기 (0) | 2022.03.07 |
[express] 개요 (1) | 2022.03.05 |