アカウントロックアウト実装

This commit is contained in:
nik.n 2024-04-02 15:42:02 +09:00
parent 80ddf8302b
commit 5d9b692982
5 changed files with 64 additions and 1 deletions

View File

@ -66,10 +66,21 @@ def login(
request: LoginModel = Depends(LoginModel.as_form),
login_service: LoginService = Depends(get_service(LoginService))
):
# ユーザーマスタ検索
pre_login_user_record = login_service.logged_in_user(request.username)
# ログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする
if pre_login_user_record is not None and pre_login_user_record.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT:
logger.info(f'ログイン失敗回数が10回以上: {request.username}')
# ユーザーが有効の場合、DBにアカウント無効にする
if pre_login_user_record.enabled_flg == 'Y':
login_service.on_retry_limit_exceeded(request.username)
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_RETRY_LIMIT_EXCEEDED)
try:
jwt_token = login_service.login(request.username, request.password)
except NotAuthorizeException as e:
logger.info(f'ログイン失敗:{e}')
login_service.incorrect_login_password_attempt(request.username)
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_ERROR)
except JWTTokenVerifyException as e:
logger.info(f'ログイン失敗:{e}')

View File

@ -25,6 +25,8 @@ class UserMasterModel(BaseDBModel):
updater: Optional[str]
update_date: Optional[datetime]
mntuser_flg: Optional[str]
mntuser_login_failed_cnt: Optional[int]
mntuser_last_login_failed_datetime: Optional[datetime]
def is_enable_user(self):
return self.enabled_flg == 'Y'

View File

@ -26,3 +26,42 @@ class UserMasterRepository(BaseRepository):
except Exception as e:
logger.exception(f"DB Error : Exception={e}")
raise e
def increase_login_retry_count(self, parameter: dict) -> UserMasterModel:
try:
query = """\
UPDATE
src05.user_mst
SET
mntuser_login_failed_cnt =
CASE
WHEN DATE(mntuser_last_login_failed_datetime) = CURRENT_DATE() THEN mntuser_login_failed_cnt + 1
ELSE 1
END,
mntuser_last_login_failed_datetime = CURRENT_DATE()
WHERE
user_id = :user_id
AND
mntuser_flg = 1;\
"""
self._database.execute(query, parameter)
except Exception as e:
logger.exception(f"DB Error : Exception={e}")
raise e
def disable_mnt_user(self, parameter: dict) -> UserMasterModel:
try:
query = """\
UPDATE
src05.user_mst
SET
enabled_flg = 'N'
WHERE
user_id = :user_id
AND
mntuser_flg = 1\
"""
self._database.execute(query, parameter)
except Exception as e:
logger.exception(f"DB Error : Exception={e}")
raise e

View File

@ -49,6 +49,12 @@ class LoginService(BaseService):
user_record: UserMasterModel = self.user_repository.fetch_one({'user_id': user_id})
return user_record
def incorrect_login_password_attempt(self, user_id: str):
self.user_repository.increase_login_retry_count({'user_id': user_id})
def on_retry_limit_exceeded(self, user_id: str):
self.user_repository.disable_mnt_user({'user_id': user_id})
def __secret_hash(self, username: str):
# see - https://aws.amazon.com/jp/premiumsupport/knowledge-center/cognito-unable-to-verify-secret-hash/ # noqa
message = bytes(username + environment.COGNITO_CLIENT_ID, 'utf-8')

View File

@ -63,6 +63,7 @@ LOGOUT_REASON_BACKUP_PROCESSING = 'dump_processing'
LOGOUT_REASON_NOT_LOGIN = 'not_login'
LOGOUT_REASON_DB_ERROR = 'db_error'
LOGOUT_REASON_UNEXPECTED = 'unexpected'
LOGOUT_REASON_RETRY_LIMIT_EXCEEDED = 'retry_limit_exceeded'
LOGOUT_REASON_MESSAGE_MAP = {
LOGOUT_REASON_DO_LOGOUT: 'Logoutしました。',
@ -72,7 +73,8 @@ LOGOUT_REASON_MESSAGE_MAP = {
LOGOUT_REASON_BACKUP_PROCESSING: 'バックアップ取得を開始しました。<br>日次バッチ更新が終了するまでマスターメンテは使用できません',
LOGOUT_REASON_NOT_LOGIN: 'Loginしてからページにアクセスしてください。',
LOGOUT_REASON_DB_ERROR: 'DB接続に失敗しました。<br>再度Loginするか、<br>管理者にお問い合わせください。',
LOGOUT_REASON_UNEXPECTED: '予期しないエラーが発生しました。<br>再度Loginするか、<br>管理者に問い合わせてください。'
LOGOUT_REASON_UNEXPECTED: '予期しないエラーが発生しました。<br>再度Loginするか、<br>管理者に問い合わせてください。',
LOGOUT_REASON_RETRY_LIMIT_EXCEEDED: 'ログイン失敗回数の上限を超えましたので<br>アカウントをロックしました。<br>管理者に連絡してください'
}
# 新規施設担当者登録CSV(マスターメンテ)
@ -207,3 +209,6 @@ DISPLAY_USER_STOP_DIV_SHORT = {
'03': '特定項目停止',
'04': '全DM停止'
}
# ログイン失敗回数上限(保守ユーザー)
LOGIN_FAIL_LIMIT = 10