• Home
  • About
    • lahuman photo

      lahuman

      열심히 사는 아저씨

    • Learn More
    • Facebook
    • LinkedIn
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

인증서버 구축기 - 2

02 Mar 2019

Reading time ~2 minutes

간단하게 DBMS 구현과 로그인 처리

인증서버 구현에 대한 설계만 하고 손도 안되고 생각만 하고 있었다.

DBMS는 다음 그림과 같은 형태로 구현했다.

AUTH server ERD

이번 시간에는 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);
        });
      }
    });
  }
});

TODO 진행 예정

  • JWT를 이용하여 로그인 성공시 전송되는 내용을 토큰 처리
  • 토큰 validate API 제공
  • 사용자 PASSWORD hash 암호화 처리(SHA-256)

나머지도 하나씩 처리 하자!

프로젝트 저장소



nodeauth Share Tweet +1