간단하게 DBMS 구현과 로그인 처리
인증서버 구현에 대한 설계만 하고 손도 안되고 생각만 하고 있었다.
DBMS는 다음 그림과 같은 형태로 구현했다.
이번 시간에는 Login API를 구현하고 테스트까지 진행한다.
모델 구현
모델을 구현하기 위하여 Sequelize Express Example를 참조 하였다.
DBMS를 참고 하여 각 모델을 다음과 같이 작성 하였다.
Users
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('Users', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
user_id: { type: DataTypes.STRING(50), allowNull: false, unique: true },
password: { type: DataTypes.STRING(100), allowNull: false },
description: { type: DataTypes.STRING(1000), allowNull: true }
}, {
freezeTableName: true,
underscored: true,
timestamps: true,
paranoid: true
});
User.associate = (models) => {
models.Users.belongsToMany(models.Roles, { through: 'UserRoles', foreignKey: 'u_id' });
};
return User;
};
Roles
module.exports = (sequelize, DataTypes) => {
var Roles = sequelize.define('Roles', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
role_name: { type: DataTypes.STRING(20), allowNull: false, unique: true },
description: { type: DataTypes.STRING(1000), allowNull: true }
}, {
freezeTableName: true,
underscored: true,
timestamps: true,
paranoid: true
});
Roles.associate = (models) => {
models.Roles.belongsToMany(models.Users, { through: 'UserRoles', foreignKey: 'r_id' });
};
return Roles;
};
UserRoles
module.exports = (sequelize, DataTypes) => {
var UserRole = sequelize.define('UserRoles', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
r_id: {
type: DataTypes.INTEGER
},
u_id: {
type: DataTypes.INTEGER
}
}, {
freezeTableName: true,
underscored: true,
timestamps: true
});
return UserRole;
};
추가적으로 LoginHistory를 구현하였고 최근 10분간 로그인이 5회 실패시 잠시 후 시도하도록 했다.
LoginHistorys
module.exports = (sequelize, DataTypes) => {
var LoginHistory = sequelize.define('LoginHistorys', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
user_id: { type: DataTypes.STRING(50), allowNull: false },
login_success: { type: DataTypes.STRING(1), allowNull: false, defaultValue:'Y' }
}, {
freezeTableName: true,
underscored: true,
timestamps: true,
paranoid: true
});
return LoginHistory;
};
로그인 구현
로그인은 간단하게 routers/index.js 에 구현하였다. 추가로 다른 기능이 생긴다면 디렉토리를 추가하여 처리 할 예정이다.
Login Process
10분동안 5회 이상의 로그인 실패가 있을 경우 잠시후 시도하라는 메시지가 표출되며, 로그인 실패/성공은 LoginHistory에 저장된다.
router.post('/login', (req, res, next) => {
const loginInfo = req.body;
if (!Object.prototype.hasOwnProperty.call(loginInfo, 'user_id')
|| !Object.prototype.hasOwnProperty.call(loginInfo, 'password')) {
res.json({ status: 'error', message: 'Invalid Prameter' });
}
else {
models.LoginHistorys.count({ where: { user_id: loginInfo.user_id, login_success: 'N', created_at: { [models.Sequelize.Op.gt]: moment().subtract(20, 'minutes').toDate() } } }).then((c) => {
if (c > 5) {
res.json({ status: 'error', message: 'Login failed several times. Please try again in 10 minutes.' });
}
else {
models.Users.findOne({
where: { user_id: loginInfo.user_id, password: loginInfo.password },
include: [models.Roles]
}).then((u) => {
if (u) {
const userInfo = {
user_id: u.user_id,
password: u.password,
desc: u.description,
role: u.Roles.map(r => r.role_name)
};
res.json({ status: 'success', userInfo });
loginInfo.login_success = 'Y';
}
else {
res.json({ status: 'error', message: 'check ID or PW' });
loginInfo.login_success = 'N';
}
models.LoginHistorys.create(loginInfo);
});
}
});
}
});