P2-19~21 지자체 수정/삭제, 비밀번호 변경, 로그인 5회 실패 lock

- P2-19: LocalGovernment edit/update/delete 추가, 목록에 수정/비활성 버튼
- P2-20: PasswordChange 컨트롤러 + View (현재 비밀번호 검증 후 변경)
- P2-21: 로그인 5회 연속 실패 시 30분 lock
  - member 테이블에 mb_login_fail_count, mb_locked_until 컬럼 추가
  - Auth::login에 lock 체크/실패 카운트 증가/성공 시 리셋 로직
- E2E 테스트 4개 전체 통과

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
javamon1174
2026-03-25 17:53:52 +09:00
parent da132f0e51
commit c2840a9e34
10 changed files with 319 additions and 4 deletions

View File

@@ -77,11 +77,33 @@ class Auth extends BaseController
->with('error', '정지된 회원입니다.');
}
if (! password_verify($password, $member->mb_passwd)) {
$this->insertMemberLog($logData, false, '비밀번호 불일치');
// P2-21: 로그인 잠금 체크 (5회 실패 시 30분 lock)
if (!empty($member->mb_locked_until) && strtotime($member->mb_locked_until) > time()) {
$remaining = ceil((strtotime($member->mb_locked_until) - time()) / 60);
$this->insertMemberLog($logData, false, '계정 잠금 상태');
return redirect()->back()
->withInput()
->with('error', '아이디 또는 비밀번호가 올바르지 않습니다.');
->with('error', '로그인 시도 횟수 초과로 계정이 잠겼습니다. 약 ' . $remaining . '분 후 다시 시도해 주세요.');
}
if (! password_verify($password, $member->mb_passwd)) {
// 실패 횟수 증가
$failCount = ((int) ($member->mb_login_fail_count ?? 0)) + 1;
$updateData = ['mb_login_fail_count' => $failCount];
if ($failCount >= 5) {
$updateData['mb_locked_until'] = date('Y-m-d H:i:s', strtotime('+30 minutes'));
}
$memberModel->update($member->mb_idx, $updateData);
$this->insertMemberLog($logData, false, '비밀번호 불일치 (' . $failCount . '회)');
$msg = '아이디 또는 비밀번호가 올바르지 않습니다.';
if ($failCount >= 5) {
$msg .= ' 5회 연속 실패로 계정이 30분간 잠깁니다.';
} elseif ($failCount >= 3) {
$msg .= ' (실패 ' . $failCount . '/5회)';
}
return redirect()->back()->withInput()->with('error', $msg);
}
// 승인 요청 상태 확인(공개 회원가입 사용자)
@@ -113,7 +135,9 @@ class Auth extends BaseController
session()->set($sessionData);
$memberModel->update($member->mb_idx, [
'mb_latestdate' => date('Y-m-d H:i:s'),
'mb_latestdate' => date('Y-m-d H:i:s'),
'mb_login_fail_count' => 0,
'mb_locked_until' => null,
]);
$this->insertMemberLog($logData, true, '로그인 성공', $member->mb_idx);