MapleStory Finger Point

Development/GUI

QSettings 로그인 알고리즘

吳鍾振 2023. 2. 21. 21:00

이 내용은 이전 글과 연관되어 있습니다.

간단한 로그인 알고리즘 중 일정 횟수 비밀번호 에러가 발생하면 해당 계정의 로그인을 일시적으로(필자는 1분으로 설정하였음) 차단하는 기능을 구현해보겠습니다.

우선 크게 필요한 것은 
첫 번째로 비밀번호 에러가 발생한 시간,
두 번째는 비밀번호 에러 횟수입니다.

현재 시간과 에러 발생 시간을 비교하여 로그인 성공 유무를 선택하는 알고리즘입니다.

자세한 것은 코드에 주석 처리 해놓았습니다.

#!/usr/bin/env python3
#
# Authors:
#     5jx2oh@gmail.com


import sys
import time
from datetime import datetime

from PySide6.QtCore import QSettings
from PySide6.QtCore import QCoreApplication, QMetaObject
from PySide6.QtWidgets import QFrame, QGridLayout, QLabel, \
    QLineEdit, QPushButton, QSizePolicy, QWidget
from PySide6.QtWidgets import QDialog, QMessageBox
from PySide6.QtCore import Qt


# Ui
class Ui_Dialog(object):
    def setupUi(self, Dialog):
        if not Dialog.objectName():
            Dialog.setObjectName(u"Dialog")
        Dialog.resize(290, 200)
        self.gridLayout = QGridLayout(Dialog)
        self.gridLayout.setObjectName(u"gridLayout")
        self.gridWidget = QWidget(Dialog)
        self.gridWidget.setObjectName(u"gridWidget")
        self.gridLayout_2 = QGridLayout(self.gridWidget)
        self.gridLayout_2.setObjectName(u"gridLayout_2")
        self.id_lineEdit = QLineEdit(self.gridWidget)
        self.id_lineEdit.setObjectName(u"id_lineEdit")
        self.id_lineEdit.setStyleSheet(u"background-color: #ffffff;")

        self.gridLayout_2.addWidget(self.id_lineEdit, 2, 0, 1, 1)

        self.alert_label = QLabel(self.gridWidget)
        self.alert_label.setObjectName(u"alert_label")
        self.alert_label.setEnabled(True)
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.alert_label.sizePolicy().hasHeightForWidth())
        self.alert_label.setSizePolicy(sizePolicy)
        self.alert_label.setStyleSheet(u"color:#ff0000;")
        self.alert_label.setFrameShadow(QFrame.Plain)
        self.alert_label.setTextFormat(Qt.AutoText)
        self.alert_label.setAlignment(Qt.AlignCenter)

        self.gridLayout_2.addWidget(self.alert_label, 5, 0, 1, 1)

        self.pw_lineEdit = QLineEdit(self.gridWidget)
        self.pw_lineEdit.setObjectName(u"pw_lineEdit")
        self.pw_lineEdit.setStyleSheet(u"background-color: #ffffff;")
        self.pw_lineEdit.setEchoMode(QLineEdit.Password)

        self.gridLayout_2.addWidget(self.pw_lineEdit, 3, 0, 1, 1)

        self.gridLayout.addWidget(self.gridWidget, 0, 0, 1, 1)

        self.login_button = QPushButton(Dialog)
        self.login_button.setObjectName(u"login_button")

        self.gridLayout.addWidget(self.login_button, 1, 0, 1, 1)

        self.retranslateUi(Dialog)
        QMetaObject.connectSlotsByName(Dialog)

    # setupUi

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Login", None))
        self.id_lineEdit.setPlaceholderText(QCoreApplication.translate("Dialog", u"ID", None))
        self.alert_label.setText("")
        self.pw_lineEdit.setPlaceholderText(QCoreApplication.translate("Dialog", u"Password", None))
        self.login_button.setText(QCoreApplication.translate("Dialog", u"Login", None))
    # retranslateUi


# Setting value
class MySetting:
    settings = QSettings('Setting', 'hi~')

    defaults = {
        'login_id': 'admin',
        'login_pw': 'admin',
        'error_time': ''
    }

    @classmethod
    def set(cls, key, value):
        cls.settings.setValue(key, value)

    @classmethod
    def get(cls, key):
        return cls.settings.value(
            key,
            cls.defaults[key],
            type(cls.defaults[key])
        )

    @classmethod
    def restore_defaults(cls):
        for key, value in cls.defaults.items():
            cls.set(key, value)


# Main Code
class LoginWindow(QDialog, Ui_Dialog):

    def __init__(self):
        super(LoginWindow, self).__init__()

        self.setupUi(self)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)

        self.login_button.clicked.connect(self.login_click)
        self.login_button.setShortcut('Return')

        self.id = MySetting.get('login_id')     # QSettings ID
        self.pw = MySetting.get('login_pw')     # QSettings 비밀번호

        self.flag = 0   # 비밀번호 에러 카운트 값

    def login_click(self):
        input_id = self.id_lineEdit.text()
        input_pw = self.pw_lineEdit.text()

        if input_id == self.id and input_pw == self.pw:     # Setting값의 ID와 PW값이 동일할 때
            if MySetting.get('error_time') != '':       # error_time 값이 Null이 아니라면, 즉 에러가 발생하였음을 의미
                now = datetime.now()    # 현재 시간
                agga = datetime.strptime(MySetting.get('error_time'), '%Y-%m-%d %H:%M:%S')
                # 에러 발생 시간을 현재 시간 Type으로 변경하여 비교할 준비
                # 아까 에러가 발생한 시간이라는 뜻으로 agga ㅎ
                diff = now - agga   # 현재 시간 - 에러 발생 시간

                if diff.seconds >= 60:      # 현재 시간과 에러가 발생한 시간의 차이가 60초 이상이면 아래 조건문 실행
                    # 즉, 비밀번호 에러가 발생한지 1분이 지났으므로 로그인이 되어야 함
                    MySetting.set('error_time', '')     # 에러 발생 시간 값을 초기화 = 에러가 발생한 적 없음
                    print('로그인 성공')
                    self.close()

                else:       # 에러가 발생한 지 아직 1분이 지나지 않았을 때
                    QMessageBox.warning(None, '계정 일시 차단', '해당 계정은 일시적으로 차단되었습니다.')
                    self.close()
                    sys.exit()

            elif MySetting.get('error_time') == '':     # 에러가 발생한 적 없을 때
                print('로그인 성공')
                self.close()

        elif input_id != self.id:     # 입력한 ID가 없을 때
            self.alert_label.setText('없는 아이디 입니다.')

        else:   # 위 조건문들에 해당되지 않을 때, 즉 ID는 맞지만 비밀번호가 틀릴 때
            if input_id == self.id:
                self.flag += 1   # 비밀번호 에러 횟수 증가
                self.alert_label.setText(f'비밀번호가 올바르지 않습니다. ({self.flag} / 5)')

            if self.flag >= 5:  # 비밀번호 에러가 5회 이상일 때
                error_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())   # 에러 발생 시간
                QMessageBox.warning(None, '비밀번호 5회 오류로 인한 계정 차단', '잠시 후에 다시 로그인을 시도해 주세요.')
                print(f'로그인 차단 시작 [{error_time}]')
                MySetting.set('error_time', error_time)     # 에러 발생 시간을 QSettings 값에 저장
                self.close()
                sys.exit()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            sys.exit()


if __name__ == '__main__':
    from PySide6.QtWidgets import QApplication

    app = QApplication(sys.argv)
    window = LoginWindow()
    window.show()
    sys.exit(app.exec())

 


기본 화면

없는 아이디

비밀번호 에러

5회 오류시 계정 차단

아직 1분이 지나지 않았을 때 계정 차단 안내

 

반응형

'Development > GUI' 카테고리의 다른 글

Grid Layout 위젯 드래그&드롭 이벤트 생성하기  (0) 2023.07.12
QSettings 사용 예제 코드  (0) 2022.07.26
PyQt5 이미지 비율 맞추기  (0) 2022.06.20
PyQt5 버튼 애니메이션  (0) 2022.06.15
PyQt5 종료 Fade out 이벤트  (0) 2021.07.08