회사에서 사용자들 수에 대한 제한을 두어서 중복 로그인 방지를 구현하게 되었다.
쿠키는 브라우저에만 남기에 중복 로그인을 쿠키로만으로는 구현할 수 없다.
세션은 데이터베이스에 저장이 되기 때문에 많은 정보를 담으면 서버에 과부하가 올 수 있다. 때문에 길이가 긴 데이터들은 jwt를 이용하였고, 키 값인 아이디만 세션에 두고 로그인 중인 사용자가 있으면 중복 로그인을 방지하게끔 구현했다.
1. 세션 관련 모듈을 설치한다.
$npm i express-session --save
$npm i express-mysql-session -- save
2. app.js에 다음과 같이 추가해준다.
...
var session = require('express-session');
var MySQLStore = require('express-mysql-session')(session);
...
var option = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PW,
port: process.env.DB_PORT,
database: process.env.DB_DATABASE,
clearExpired: true,
checkExpirationInterval: 10000,
expiration: 10000
}
var sessionStore = new MySQLStore(option);
app.use(session({
secret: process.env.secret,
resave: false,
saveUninitialized: true,
store: sessionStore
}))
option 중 세션에 관한 내용을 살펴보면,
- clearExpired : 유효기간이 지난 세션을 삭제한다.
- checkExpirationInterval : 세션의 유효기간을 체크하는 시간을 설정한다.
- expiration : 세션의 유효기간을 설정한다.
3. 라우터에서의 사용법은 다음과 같다.
router.get("/", function (req, res, next) {
req.session.uid = "uid" // 세션 생성
delete req.session.uid // 세션 삭제
res.send({success : true })
});
보통은 로그인을 한 정보를 쿠키에 담는다. 그 후에 로그인 정보가 쿠키에 있으면 별도의 로그인 화면 없이 바로 메인 화면으로 가게끔 편의성을 위해 구현해둔 경우도 있다.
먼저 우리는 로그인을 할 때 쿠키에 로그인 정보를 담기 이전에 세션에 이미 로그인 중인 데이터가 있는지 확인할 것이다.
그리고 데이터가 없으면 쿠키에 로그인 정보를 담고 로그인에 성공한다.
세션이 생기는 경로는 로그인밖에 없지만 세션이 삭제되어야하는 경우는 두 가지가 있다.
- 로그아웃을 해서 세션을 삭제
- 세션의 expiration 시간이 지나면 자동으로 삭제
이미 위에서 세션의 유효시간을 설정했기 때문에 두 번째의 경우는 설정이 따로 필요없다. 하지만 로그아웃 버튼을 클릭했을 때는 우리가 직접 쿼리로 삭제해주어야 한다.
그러기 위해 먼저 sequelize model에 sessions 파일을 추가해준다. sequelize에 대한 내용은 다음 포스트를 참고하자.
https://typo.tistory.com/entry/MySQL-CRUD-with-Reactjs-and-Nodejs-Back-End1?category=905676
sequelize/models/sessions.js
module.exports = (sequelize, DataTypes) => {
const Sessions = sequelize.define("Sessions", {
session_id: {
type: DataTypes.STRING,
primaryKey: true,
},
expires: {
type: DataTypes.STRING
},
data: {
type: DataTypes.STRING
},
}, {
charset: "utf8", // 한국어 설정
collate: "utf8_general_ci", // 한국어 설정
tableName: "sessions", // 테이블 이름
timestamps: false, // createAt & updateAt 활성화
});
return Sessions;
};
4. 로그인과 로그아웃을 구성해준다.
const { QueryTypes, sequelize } = require('sequelize');
const db = require('../sequelize/models');
router.get("/login", function (req, res, next) {
// 로그인 정보가 있는지 확인
...
// 세션이 존재하는지 확인
const select_data_query = `SELECT JSON_EXTRACT(data, '$.uid') as uid FROM SESSIONS WHERE JSON_EXTRACT(data, '$.uid') = :uid`
db.sequelize.query(
select_data_query,
{
replacements: { uid: "teepo" },
type: QueryTypes.SELECT
}
).then((result) => {
// 세션이 존재하지 않을 경우
if(result.length === 0) {
// 세션 생성
req.session.uid = "teepo"
// jwt 토큰 사용자면 jwt 토큰 생성
// 쿠키 생성
res.cookie('isLogined', {"uid": "teepo"}, { maxAge: 86400000, path: "/", httpOnly: true });
res.send({success : true})
}
// 세션이 존재할 경우
else {
return res.send({success : false, result : "이미 접속중인 사용자입니다."})
}
})
});
router.get("/logout", function (req, res, next) {
// 세션에 존재하는 uid 데이터와 일치하는 데이터 삭제
const delete_data_query = `DELETE FROM SESSIONS WHERE JSON_EXTRACT(data, '$.uid') = :uid`
db.sequelize.query(
delete_data_query,
{
replacements: { uid: req.session.uid },
type: QueryTypes.DELETE
}
).then((result) => {
// 세션 삭제
delete req.session.uid;
// 쿠키 삭제
res.clearCookie('isLogined');
res.send({ success: true }); // 클라이언트에 결과 반환
}).catch((err) => {
console.log(err)
})
});
'DB > MySQL' 카테고리의 다른 글
MySQL | Connection 문제 해결 (0) | 2021.12.21 |
---|---|
MySOL | MariaDB timeout 설정 (0) | 2021.12.20 |
MySQL | CRUD with Node.js | Update and Delete (0) | 2021.12.09 |
MySQL | CRUD with Node.js | Find (0) | 2021.12.08 |
MySQL | CRUD with Node.js | Create (0) | 2021.12.08 |