일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 자바스크립트
- JavaScript
- localstorage
- 지금 자면 꿈을 꾸지만
- pm2
- 백준 28303번
- 그리디
- 게임 서버 아키텍처
- 더 흔한 색칠 타일 문제
- 백준 32029번
- Prisma
- Next
- HTTP
- Github
- Express.js
- ccw 알고리즘
- branch
- 백준 32028번
- ERD
- insomnia
- ucpc 2023 예선 i번
- ucpc 2024 예선 e번
- map
- MongoDB
- html5
- string
- MySQL
- PROJECT
- ucpc 2023 예선 d번
- router
Archives
- Today
- Total
dh_0e
[Node.js] 강의 내용 개념 정리(5) (인증, 인가, 사용자 인증 미들웨어) 본문
인증(Authentication)
- 인증은 서비스를 이용하려는 사용자가 인증된 신분을 가진 사람이 맞는지 검증하는 작업을 뜻하며 일반적으로 신분증 검사 작업에 해당함
인가(Authorization)
- 인가는 이미 인증된 사용자가 특정 리소스에 접근하거나 특정 작업을 수행할 수 있는 권한이 있는지를 검증하는 작업을 뜻하며 놀이공원에서 자유 이용권을 소지하고 있는지 확인하는 단계로 볼 수 있음
- 사용자 인증 미들웨어를 통해서 구현함
bcrypt 모듈
- 입력받은 데이터를 특정 암호화 알고리즘을 이용하여 암호화 및 검증을 도와주는 모듈
- 비밀번호를 bctypt를 이용해 암호화하게 된다면 특정한 문자열로 변환됨
- 이 변환된 문자열은 단방향 암호화되어 원래의 비밀번호로 복수할 수 없게됨
bcrypt 암호화
import bcrypt from 'bcrypt';
const password = 'Sparta'; // 사용자의 비밀번호
const saltRounds = 10; // salt를 얼마나 복잡하게 만들지 결정합니다.
// 'hashedPassword'는 암호화된 비밀번호 입니다.
const hashedPassword = await bcrypt.hash(password, saltRounds);
console.log(hashedPassword);
bcrypt 복호화
import bcrypt from 'bcrypt';
const password = 'Sparta'; // 사용자가 입력한 비밀번호
const hashed = '$2b$10$OOziCKNP/dH1jd.Wvc3JluZVm7H8WXR8oUmxUQ/cfdizQOLjCXoXa'; // DB에서 가져온 암호화된 비밀번호
// 'result'는 비밀번호가 일치하면 'true' 아니면 'false'
const result = await bcrypt.compare(password, hashed);
console.log(result); // true
// 비밀번호가 일치하지 않다면, 'false'
const failedResult = await bcrypt.compare('FailedPassword', hashed);
console.log(failedResult); // false
이를 이용한 회원가입 / 로그인 구현
/** 사용자 회원가입 API **/
router.post("/sign-up", async (req, res, next) => {
const { email, password, name, age, gender, profileImage } = req.body;
const isExistUser = await prisma.users.findFirst({
where: { email },
});
if (isExistUser) {
console.log(isExistUser.email);
return res
.status(409)
.json({ errorMessage: "이미 존재하는 이메일입니다." });
}
const hashedPassword = await bcrypt.hash(password, 10);
const user = await prisma.users.create({
data: {
email,
password: hashedPassword,
},
});
const userInfo = await prisma.userInfos.create({
data: {
UserId: user.userId,
name,
age,
gender: gender.toUpperCase(),
profileImage,
},
});
return res.status(201).json({ message: "회원가입이 완료되었습니다." });
});
/* 로그인 API */
router.post("/sign-in", async (req, res, next) => {
const { email, password } = req.body;
const user = await prisma.users.findFirst({ where: { email } });
if (!user) {
return res
.status(401)
.json({ errorMessage: "존재하지 않는 이메일입니다." });
}
if (!(await bcrypt.compare(password, user.password))) {
return res
.status(401)
.json({ errorMessage: "비밀번호가 일치하지 않습니다." });
}
const token = jwt.sign(
{
userId: user.userId,
},
"Secret Key"
);
res.cookie("authorization", `Bearer ${token}`);
return res.status(200).json({ message: "로그인 성공했습니다." });
});
사용자 인증 미들웨어
- 클라이언트로 전달받은 쿠키를 검증하는 작업을 수행
- 클라이언트가 제공한 쿠키에 담겨있는 JWT를 이용해 사용자를 조회
사용자 인증 미들웨어 비즈니스 로직
- 클라이언트로부터 쿠키를 전달받음
- 쿠키가 Bearer 토큰 형식인지 확인함
- 서버에서 발급한 JWT가 맞는지 검증함
- JWT의 userId를 이용해 사용자를 조회
- req.user에 조회된 사용자 정보를 할당
- 다음 미들웨어(next) 실행
ex)
import jwt from "jsonwebtoken";
import { prisma } from "../utils/prisma/index.js";
export default async function (req, res, next) {
try {
const { authorization } = req.cookies;
console.log(authorization);
const [tokenType, token] = authorization.split(" ");
console.log(tokenType);
if (tokenType !== "Bearer")
throw new Error("토큰 타입이 일치하지 않습니다.");
const decodedToken = jwt.verify(token, "Secret Key");
const userId = +decodedToken.userId;
const user = await prisma.users.findFirst({
where: { userId },
});
if (!user) throw new Error("토큰 사용자가 존재하지 않습니다.");
req.user = user;
next();
} catch (error) {
res.clearCookie("authorization");
switch (error.name) {
case "TokenExpiredError": // 토큰이 만료되었을 때 발생하는 에러
return res.status(401).json({ errorMessage: "토큰이 만료되었습니다." });
case "JsonWebTokenError": // 토큰 검증이 실패했을 때, 발생하는 에러
return res
.status(401)
.json({ errorMessage: "토큰 인증에 실패하였습니다." });
default:
return res
.status(401)
.json({
errorMessage: error.errorMessage ?? "비 정상적인 요청입니다.",
});
}
}
}
이를 이용한 사용자 정보 조회
/* 사용자 조회 API */
router.get("/users", authMiddleware, async (req, res, next) => {
const { userId } = +req.user;
const user = await prisma.users.findFirst({
where: { userId },
select: {
userId: true,
email: true,
createdAt: true,
updatedAt: true,
UserInfos: {
select: {
name: true,
age: true,
gender: true,
profileImage: true,
},
},
},
});
return res.status(200).json({ data: user });
});
- 위와 같이 중첩 select 문법은 SQL의 JOIN과 동일한 역할을 수행함
- 중첩 select 문법을 사용하기 위해선 Prisma model에서 @relation()과 같이 관계 설정이 되어야 함
'내일배움캠프 > Node.js[숙련]' 카테고리의 다른 글
[Node.js] 강의 내용 개념 정리(7) (로그 미들웨어, Transaction) (0) | 2024.05.28 |
---|---|
[Node.js] 강의 내용 개념 정리(6) (Access Token, Refresh Token) (0) | 2024.05.27 |
[Node.js] 강의 내용 개념 정리(4) (JWT) (0) | 2024.05.24 |
[Node.js] 강의 내용 개념 정리(3) (Cookie, Session) (0) | 2024.05.24 |
[Node.js] 강의 내용 개념 정리(2) (Prisma) (0) | 2024.05.23 |