Express에서 redis를 session storage로 사용 해서 로그인 / 로그아웃 구현해보기
- 기존에 세션을 메모리에 저장해서 로그인/로그아웃 하던 시스템을 세션을 레디스에 저장하도록 변경!
1. 로컬에 Redis 설치 및 실행
1-1. Redis Stack 설치
>> stack은 레디스 서버 및 여러가지를 한번에 스택으로 제공한다는 것
>> 레디스 서버는 7버전 임
>> 저는 macOS에서 설치 후 진행
https://redis.io/docs/getting-started/install-stack/mac-os/
1-2. Redis 서버 실행
실행 명령어 : redis-stack-server
>> 백그라운드에서 실행 : nohup redis-stack-server &
종료 명령어 :
>> 프로세스 확인 : ps aux | grep redis
>> 프로세스 종료 : kill [PID]
※ Redis-Stack에 포함된 Redis 서버 UI인 RedisInsight를 실행 (초보자라 UI 환경 사용)
실행 명령어 : redisinsight
※ Redis-Stack으로 설치 후 Redis 설정을 하고싶다면
https://yonguri.tistory.com/148 참고
2. 프로젝트에 npm 패키지 설치
설치 명령어 : npm i connect-redis redis
✓ connect-redis:
Express에서 redis를 session storage로 제공하는 라이브러리 (CommonJS(require) 및 ESM(import) 모듈을 모두 지원)
https://www.npmjs.com/package/connect-redis
✓ redis:
Express에서 redis client를 생성할 수 있는 라이브러리 (레디스서버에 연결하는데 필요)
https://www.npmjs.com/package/redis?activeTab=readme
✓ 구현할때 사용한 버전들
이번에는 CommonJS 및 레디스7 버전을 사용
{
"express": "^4.18.2",
"express-session": "^1.17.3",
"redis": "^4.6.10",
"connect-redis": "^7.1.0",
}
3. 코드에 적용 해보기
- redis 패키지로 redisClient 생성 및 redis서버에 connect
- '생성한 redisClient' + 'connect-redis 패키지' 를 사용해서 redisStore 객체 생성
- 생성한 redisStore를 session의 저장소로 설정
const dotenv = require('dotenv');
dotenv.config();
const { PORT, REDIS_HOST, REDIS_PORT, SESSION_KEY } = process.env;
const express = require('express');
const session = require('express-session');
const app = express();
// redis 버전 7에서 commonJS 형식
const redis = require('redis');
const RedisStore = require('connect-redis').default;
// main APP
async function main() {
const redisClient = await redis
.createClient({
// 목적지 레디스 서버에 대한 정보를 적지 않으면 기본값으로 localhost 6379포트로 연결
url: `redis://@${REDIS_HOST}:${REDIS_PORT}`,
// 그외 목적지 레디스 서버 정보는
// format : redis[s]://[[username][:password]@][host][:port][/db-number]
// createClient({
// url: 'redis://alice:foobared@awesome.redis.server:6380'
// });
})
.on('connect', () => console.log('Initiating a connection to the server '))
.on('ready', () => {
console.log('Client is ready to use');
})
.on('end', () => {
console.log('Connection has been closed');
})
.on('error', (err) => console.log('Redis Client Error', err))
.on('reconnecting', () => {
console.log('Client is trying to reconnect to the server ');
})
.connect();
//// redis에서 키, 밸류 가져오기
// const value = await redisClient.get('key');
//// redis에 키, 밸류 저장하기
// await redisClient.set('key', 'value');
// await redisClient.set('key', 'value', {
// EX: 10,
// NX: true
//});
//// 트랜잭션(Multi/Exec)
// .multi()를 호출하여 트랜잭션을 시작한 다음 명령을 연결합니다.
// 완료되면 .exec()를 호출하면 결과가 포함된 배열이 반환됩니다.
// 그니까 set 과 get을 함께한다. -> set 과 get의 결과를 배열로 한번에 받는다
// await client.set('another-key', 'another-value');
// const [setKeyReply, otherKeyValue] = await client
// .multi()
// .set('key', 'value')
// .get('another-key')
// .exec(); // ['OK', 'another-value']
//// 연결 끊기 quit()
// 서버에 QUIT 명령을 전송하여 Redis에 대한 클라이언트 연결을 정상적으로 종료합니다.
// 종료하기 전에 클라이언트는 대기열에 남아 있는 모든 명령을 실행하고 각 명령에 대해 Redis로부터 응답을 받습니다.
// 비동기 처리
// const [ping, get, quit] = await Promise.all([
// client.ping(),
// client.get('key'),
// client.quit()
// ]); // ['PONG', null, 'OK']
// 비동기 처리 및 에러시 처리까지
// try {
// await client.get('key');
// } catch (err) {
// // ClosedClient Error
// }
//// 연결 끊기 disconnect()
// await redisClient.disconnect();
let redisStore = new RedisStore({
client: redisClient,
// prefix: 'myapp:',
});
app.use(
session({
secret: SESSION_KEY,
resave: false, // 필수옵션 : 경량 세션을 강제로 활성화
saveUninitialized: false, // 권장사항: 데이터가 존재할 때만 세션을 저장
cookie: {
httpOnly: true,
maxAge: 60 * 60000, // 1h
},
store: redisStore,
})
);
app.set('view engine', 'ejs');
app.use('/views', express.static(__dirname + '/views'));
app.use('/static', express.static(__dirname + '/static'));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
// 레디스 연결을 확인 및 재연결 시도하는 미들웨어
app.use((req, res, next) => {
// if (!redisClient.connected) {
if (!redisClient.connect) {
redisClient.connect();
}
next();
});
const router = require('./routes/user');
app.use('/', router);
// TODO: 404 에러 처리
app.get('*', (req, res) => {
res.render('404');
});
app.listen(PORT, () => {
console.log(`http://localhost:${PORT}`);
});
}
main();
4. 로그인 / 로그아웃 테스트 후 Redis서버에 유저정보인 세션 데이터가 저장되는지 확인
- 로그인 시도
- 로그인 후 redis 서버에 저장된 데이터
- 1시간으로 설정한 세션 유효시간과 로그인한 유저의 아이디가 레디스에 저장된것을 확인
- 끝 -
'Nodejs' 카테고리의 다른 글
[Nodejs] Express JWT 토큰 발급/검증 (0) | 2023.10.19 |
---|---|
[nodejs] Express-session (0) | 2023.10.16 |
[Nodejs] 싱글 스레드 (1) | 2023.10.04 |
[Nodejs] 동기/비동기, 블로킹/논블로킹 (0) | 2023.10.02 |
[Nodejs] Event-driven (이벤트기반) (0) | 2023.09.30 |