AuthController.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. namespace App\Controllers\Api;
  3. use CodeIgniter\HTTP\ResponseInterface;
  4. class AuthController extends BaseApiController
  5. {
  6. /**
  7. * Login
  8. */
  9. public function login()
  10. {
  11. $json = $this->request->getJSON();
  12. $username = $json->username ?? '';
  13. $password = $json->password ?? '';
  14. if (empty($username) || empty($password)) {
  15. return $this->respondError('아이디와 비밀번호를 입력하세요.');
  16. }
  17. // Find admin user
  18. $builder = $this->getDB()->table('admin_users');
  19. $admin = $builder->where('username', $username)->get()->getRow();
  20. if (!$admin) {
  21. return $this->respondError('아이디 또는 비밀번호가 올바르지 않습니다.');
  22. }
  23. // Check if account is locked (5 failed attempts)
  24. $loginAttempts = $admin->login_attempts ?? 0;
  25. if ($loginAttempts >= 5) {
  26. return $this->respondError('계정이 잠겼습니다. 슈퍼 관리자에게 문의하여주세요.', ResponseInterface::HTTP_FORBIDDEN);
  27. }
  28. // Check if admin is active
  29. if ($admin->status !== 'active') {
  30. return $this->respondError('비활성화된 계정입니다. 관리자에게 문의하세요.');
  31. }
  32. // Verify password
  33. if (!password_verify($password, $admin->password)) {
  34. // Increment login attempts
  35. $newAttempts = $loginAttempts + 1;
  36. $updateBuilder = $this->getDB()->table('admin_users');
  37. $updateBuilder->where('id', $admin->id)->update([
  38. 'login_attempts' => $newAttempts,
  39. 'last_failed_login' => date('Y-m-d H:i:s')
  40. ]);
  41. // Check if account should be locked
  42. if ($newAttempts >= 5) {
  43. return $this->respondError('비밀번호를 5회 틀렸습니다. 계정이 잠겼습니다. 슈퍼 관리자에게 문의하여주세요.', ResponseInterface::HTTP_FORBIDDEN);
  44. }
  45. $remainingAttempts = 5 - $newAttempts;
  46. return $this->respondError("아이디 또는 비밀번호가 올바르지 않습니다. (남은 시도 횟수: {$remainingAttempts}회)");
  47. }
  48. // Reset login attempts on successful login
  49. $resetBuilder = $this->getDB()->table('admin_users');
  50. $resetBuilder->where('id', $admin->id)->update([
  51. 'login_attempts' => 0,
  52. 'last_failed_login' => null
  53. ]);
  54. // Generate token
  55. $token = bin2hex(random_bytes(32));
  56. $expiresAt = date('Y-m-d H:i:s', strtotime('+24 hours'));
  57. // Save token
  58. $tokenBuilder = $this->getDB()->table('admin_tokens');
  59. $tokenBuilder->insert([
  60. 'admin_id' => $admin->id,
  61. 'token' => $token,
  62. 'expires_at' => $expiresAt,
  63. 'created_at' => date('Y-m-d H:i:s')
  64. ]);
  65. // Check if password change is needed (6 months)
  66. $passwordChangeNeeded = false;
  67. if (!empty($admin->password_changed_at)) {
  68. $sixMonthsAgo = strtotime('-6 months');
  69. $passwordChangedTime = strtotime($admin->password_changed_at);
  70. $passwordChangeNeeded = $passwordChangedTime < $sixMonthsAgo;
  71. } else {
  72. // password_changed_at이 없으면 created_at 기준으로 체크
  73. if (!empty($admin->created_at)) {
  74. $sixMonthsAgo = strtotime('-6 months');
  75. $createdTime = strtotime($admin->created_at);
  76. $passwordChangeNeeded = $createdTime < $sixMonthsAgo;
  77. }
  78. }
  79. return $this->respondSuccess([
  80. 'token' => $token,
  81. 'expires_at' => $expiresAt,
  82. 'password_change_needed' => $passwordChangeNeeded,
  83. 'admin' => [
  84. 'id' => $admin->id,
  85. 'username' => $admin->username,
  86. 'name' => $admin->name,
  87. 'email' => $admin->email
  88. ]
  89. ], '로그인 성공');
  90. }
  91. /**
  92. * Logout
  93. */
  94. public function logout()
  95. {
  96. $tokenData = parent::validateToken();
  97. if ($tokenData) {
  98. $builder = $this->getDB()->table('admin_tokens');
  99. $builder->where('token', $tokenData->token)->delete();
  100. }
  101. return $this->respondSuccess(null, '로그아웃 성공');
  102. }
  103. /**
  104. * Check token (API endpoint)
  105. */
  106. public function check()
  107. {
  108. $tokenData = $this->requireAuth();
  109. if ($tokenData instanceof ResponseInterface) {
  110. return $tokenData;
  111. }
  112. // Get admin info
  113. $builder = $this->getDB()->table('admin_users');
  114. $admin = $builder->where('id', $tokenData->admin_id)->get()->getRow();
  115. return $this->respondSuccess([
  116. 'admin' => [
  117. 'id' => $admin->id,
  118. 'username' => $admin->username,
  119. 'name' => $admin->name,
  120. 'email' => $admin->email
  121. ]
  122. ]);
  123. }
  124. }