1. Authentication(인증)
- session & cookie
- 쿠키
: 클라이언트 컴퓨터에 저장되는 작은 데이터 조각
: 서버로부터 전송되어 웹브라우저에 저장
: 텍스트 형식으로 주로 사용자 인증, 설정, 장바구니 등에 사용
- 세션
: 웹서버 측에서 유지되는 상태 정보
: 사용자에 대한 고유한 세션ID를 통해 식별
: 서버 메모리 또는 데이터베이스에 저장 가능
2. bcrypt
- 해시 함수를 사용하여 비밀번호를 안전하게 저장하는데 사용되는 암호화 라이브러리
- 단방향 해시 함수로 한번 해시된 값을 다시 원래 값으로 역추적하는 것이 불가능
- 솔트(salt): 해시에 고유한 솔트 값을 추가하여 보안성을 높임. 같은 비밀번호를 가진 사용자가 있더라도 서로 다른 해시값을 가짐
- 작업인자(Adaptive Work Factor): 매개변수를 조정하여 해시 작업의 복잡성을 조절. 암호 분석학적으로 안전한 해시 함수를 유지하면서도 암호화 작업에 필요한 시간을 조절할 수 있게 함
- 해시함수
임의의 길이의 데이터를 받아서 고정된 길이의 고유한 값으로 변환하는 함수.
이러한 변환된 값은 해시 값 또는 해시 코드라고 함
ㄴ 동일한 입력에 대해 항상 동일한 해시 값을 생성
ㄴ 항상 고정된 출력 길이를 생성
ㄴ 해시된 값을 통해 원본 값을 복구할 수 없음
- bycrypt 설치하기
npm i bycrypt
< bycrypt.js >
import * as bcrypt from "bcrypt";
const password = 'abcd1234';
const hashed = bcrypt.hashSync(password, 10)
//hashSync(매개변수, 솔트값) // 솔트값: 숫자가 높을 수록 속도가 느림 // 10이하 추천
console.log(`password: ${password}, hashed: ${hashed}`);
const result = bcrypt.compareSync('abcd1234',hashed);
console.log(result);
</ bycrypt.js >
password: abcd1234, hashed: $2b$10$AtpdctSuxE7u7TNwi71Rz./uKFq9dABJY.lLgo5LvDdJN9h6Du0Jy true |
- 문제
controller/auth.js 에서 login()를 bcrypt를 적용하여 로그인 프로세스를 만들어보자
< data > auth.js >
let users = [
{
id: '1',
username : "apple",
password: "$2b$10$AtpdctSuxE7u7TNwi71Rz./uKFq9dABJY.lLgo5LvDdJN9h6Du0Jy",
name: "김사과",
email: "apple@apple.com",
},
</ data > auth.js >
먼저, password: "1111"을 " $2b$10$AtpdctSuxE7u7TNwi71Rz./uKFq9dABJY.lLgo5LvDdJN9h6Du0Jy" 으로 변경(hashed 값) userid를 username으로 변경 |
< controllar> auth.js >
import * as authRepository from "../data/auth.js";
import bcrypt from 'bcrypt'; //추가
// 로그인하는 함수 //수정
export async function login(req, res, next){
const { username, password } = req.body;
const user = await authRepository.login(username);
// const bcryptPW = bcrypt.hashSync(password, 10);
// const result = bcrypt.compareSync('abcd1234', bcryptPW);
if(user){
if(bcrypt.compareSync(password, user.password)){
res.status(201).json(`${username} 로그인 완료`);
}
else{
res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
}
}
// else{
// res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
// }
}
</ controllar> auth.js >
3. JWT(JSON Web Token)
- 웹 애플리케이션과 서비스 간에 정보를 안전하게 전달하기 위한 인증 및 권한 매커니즘을 구현하는데
사용하는 표준화된 방법 중 하나
- 인증 및 정보 교환을 위한 토큰 기반의 인증 방식 중 하나
- JSON 포멧을 사용하여 정보 표현, 서명 및 암호화를 통해 정보의 무결성 보장
- Base 64로 인코딩된 JSON 객체이며 사용자 정보 및 기타 데이터를 안전하게 전송하기 위해 사용
- header: JWT의 유형과 해당 알고리즘이 포함
- { Header | Payload | Signature }
- Header: 토큰 유형 및 서명 알고리즘과 같은 메타데이터가 포함
- Payload: 토큰에 포함될 데이터가 들어있는 부분
- Signature: 헤더, 페이로드 및 비밀키를 사용하여 생성된 서명으로 토큰의 무결성을 검증하는데 사용
- JSON Web Token(JWT) 설치
npm i jsonwebtoken
- JSON Web Token(JWT) _ 토큰을 생성하고 유효성을 확인
< jwt.js >
import jwt from 'jsonwebtoken';
const secret='abcdefg1234%^&*';
const token = jwt.sign(
{
id:'apple',
isAdmin:false
},
secret,
{expiresIn: "1h"} // 얼마만큼 토근이 유지될 것인가
);
//expiresIn: "1h"
//expiresIn: 2 유지되다 에러
setTimeout(()=>{
jwt.verify(token,secret,(error,decoded)=>{
console.log(error,decoded);
});
}, 3000); // 3초마다 찍어주기
console.log(token);
</jwt.js >
{expiresIn: "1h"} 결과 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFwcGxlIiwiaXNBZG1pbiI6ZmFsc2UsImlhdCI6MTcxNDQ0NzkyMywiZXhwIjoxNzE0NDUxNTIzfQ.C_7E0JO2LEqIEEdUi9YfMa0BgPod7xJcCPvZBUShWeo null { id: 'apple', isAdmin: false, iat: 1714447923, exp: 1714451523 } |
{expiresIn: 2} 결과 |
- Header: JWT의 유형과 해싱 알고리즘이 포함
{ "alg" : "HS256", "typ" : "JWT" } |
- Payload: 토큰에 담긴 정보가 포함
{ "alg" : "HS256", "typ" : "JWT" } |
{
id:'apple',
isAdmin:false
},
- Signatur: 해더와 페이포드를 인코딩하고 비밀키를 사용하여 서명되 문자열. 서명은 토큰이 변조되지 않았음을 확인하는데 사용
- Sign()
jsonwebtoken.sign(payload, secretOrPrivatekey, [option, callback])
payload: JWT에 포함될 페이로드 데이터 secretOrPrivatkey: JWT 서명하기 위해 사용될 비밀 키 또는 개인 키 |
- 문제
jwt.js를 참고하여 controller/auth.js에 토큰을 발행하고 login() 에 로그인이 완료되면
클라이언트에 토근을 출력하는 프로세스를 만들어보자
< controller > auth.js >
import * as authRepository from "../data/auth.js";
import bcrypt from 'bcrypt';
import jsonwebtoken from 'jsonwebtoken' ; //추가
const secret = "abcd1234%^&*" //추가
//jwt 토근 //추가
async function makeToken(id){
const token = jwt.sign({
id: id,
isAdmin: false
}, secret, {expireIn:'1h'})
return token;
}
// 회원가입 함수 //수정
export async function signup(req, res, next){
const { username, password, name, email } = req.body;
const hashed = bcrypt.hashSync(password, 10); //추가
const users = await authRepository.createUser(username, hashed, password, name, email); //hashed 추가
if(users){
res.status(201).json(users);
}
}
// 로그인하는 함수 //수정
export async function login(req, res, next){
const { username, password } = req.body;
const user = await authRepository.login(username);
// const bcryptPW = bcrypt.hashSync(password, 10);
// const result = bcrypt.compareSync('abcd1234', bcryptPW);
if(user){
if(bcrypt.compareSync(password, user.password)){
//res.status(201).json(`${username} 로그인 완료`); //지우기
res.status(201).header('Token',makeToken(username)).json(`${username} 로그인 완료`) //토큰값만들기 //추가
}
else{
res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
}
}else{
res.status(404).json({ message: `${username} 님 아이디 또는 비밀번호를 확인해주세요` });
}
}
//토큰 확인 //추가
export async function verify(req, res, next){
const token = req.header['Token'];
if(token){
res.status(200).json(token);
}
}
</ controller > auth.js >
< router > auth.js >
import express from 'express';
import { body } from 'express-validator';
import * as authController from "../controller/auth.js";
import { validate } from "../middleware/validator.js";
const router = express.Router();
const validateSignup = [
body('username').trim().isLength({ min: 3 }).withMessage('최소 3자 이상 입력'),
body('password').trim().isLength({ min: 4 }).withMessage('최소 4자 이상 입력'),
body('email').trim().isEmail().withMessage('이메일 형식 확인'),
validate
]
router.post('/signup', validateSignup, authController.signup);
router.post('/login', authController.login);
router.get('/me', authController.verify); //추가
export default router;
</ router > auth.js >
- git-hub에 commit 하기
'Web > Node.js' 카테고리의 다른 글
15. 환경변수, 웹소켓 (0) | 2024.05.03 |
---|---|
14. Postman 정리, 아이디 중복체크 (0) | 2024.05.02 |
12. Validate(데이터 검증) (0) | 2024.04.29 |
11. 리팩토링 (0) | 2024.04.26 |
10. 실습: Tweet (0) | 2024.04.26 |