| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- <?php
- namespace App\Controllers;
- use CodeIgniter\RESTful\ResourceController;
- use App\Libraries\JwtLib\JWT;
- use App\Libraries\JwtLib\Key;
- use App\Models\LoginModel;
- class Roulette extends ResourceController
- {
- public function login()
- {
- // JSON 데이터 받기
- $data = $this->request->getJSON(true);
- $id = $data['id'] ?? null;
- $password = $data['password'] ?? null;
- $logintype = $data['logintype'] ?? null;
- if (!$id || !$password) {
- return $this->fail([
- 'errorCode' => 1000,
- 'message' => '아이디 또는 비밀번호가 누락되었습니다.'
- ], 400);
- }
- $loginModel = new LoginModel();
- $builder = $loginModel->getBuilderFor($logintype); // 모델을 통해 빌더를 가져옴
-
- $user = $builder->where('ID', $id)->get()->getRowArray();
- if (!$user) {
- return $this->fail([
- 'errorCode' => 1001,
- 'message' => '존재하지 않는 아이디입니다.'
- ], 404);
- }
- // 비밀번호 검증
- if (!password_verify($password, $user['PASSWORD'])) {
- return $this->fail([
- 'errorCode' => 1002,
- 'message' => '비밀번호가 틀렸습니다.'
- ], 401);
- }
- unset($user['PASSWORD']); // 비밀번호 노출 방지
- // JWT 토큰 생성에 필요한 값 로드
- $jwtSecret = env('JWT_SECRET');
- $kid = env('JWT_KID');
- if (empty($jwtSecret) || empty($kid)) {
- return $this->failServerError('환경변수가 누락되었습니다. 관리자에게 문의하세요.');
- }
- if (!class_exists('\App\Libraries\JwtLib\JWT')) {
- return $this->failServerError('JWT 라이브러리를 찾을 수 없습니다.');
- }
- $issuedAt = time();
- $accessExpire = $issuedAt + 60 * 15; // 15분
- //$accessExpire = $issuedAt + 5; // 15분
- $refreshExpire = $issuedAt + 60 * 60 * 24 * 14; // 14일
- //$refreshExpire = $issuedAt + 5; // 14일
- $accessPayload = [
- 'iat' => $issuedAt,
- 'exp' => $accessExpire,
- 'sub' => $user['ID'],
- 'name' => $user['NAME'] ?? '',
- ];
- // 리프레시 토큰 existing check
- $currentRefreshToken = $user['REFRESH_TOKEN'] ?? null;
- $validRefreshToken = null;
- // 토큰이 **없거나** (빈 값, null), 존재하지만 만료된 경우 모두 새로 발급
- $needIssueRefresh = !$currentRefreshToken; // null 또는 빈 문자열 등
- if ($currentRefreshToken) {
- // 기존 리프레시 토큰 유효성 검사
- try {
- $key = new Key($jwtSecret, 'HS256');
- $decoded = JWT::decode($currentRefreshToken, $key);
- if (isset($decoded->exp) && $decoded->exp > time()) {
- // 만료되지 않음, 재사용
- $validRefreshToken = $currentRefreshToken;
- $needIssueRefresh = false;
- } else {
- // 만료됨
- $needIssueRefresh = true;
- }
- } catch (\Throwable $e) {
- // 토큰이 변조됐거나 잘못된 경우에도 새로 발급
- $needIssueRefresh = true;
- }
- }
- if ($needIssueRefresh) {
- // 없거나 만료/무효화 시 새로 발급 및 DB 업데이트
- $refreshPayload = [
- 'iat' => $issuedAt,
- 'exp' => $refreshExpire,
- 'sub' => $user['ID'],
- ];
- try {
- $validRefreshToken = JWT::encode($refreshPayload, $jwtSecret, 'HS256', $kid);
- // ADM_LIST에 리프레시 토큰 값 업데이트 (신규 발급 포함)
- $builder->where('ID', $user['ID'])->update(['REFRESH_TOKEN' => $validRefreshToken]);
- } catch (\Throwable $e) {
- return $this->failServerError('JWT 생성 오류: ' . $e->getMessage());
- }
- }
- try {
- $accessToken = JWT::encode($accessPayload, $jwtSecret, 'HS256', $kid);
- } catch (\Throwable $e) {
- return $this->failServerError('JWT 생성 오류: ' . $e->getMessage());
- }
- return $this->respond([
- 'status' => 'active',
- 'accessToken' => $accessToken,
- 'refreshToken' => $validRefreshToken,
- 'user' => $user,
- ]);
- }
- public function refreshToken()
- {
- $data = $this->request->getJSON(true);
- $refreshToken = $data['refreshToken'] ?? null;
- if (!$refreshToken) {
- return $this->fail('리프레시 토큰이 필요합니다.', 400);
- }
- $jwtSecret = env('JWT_SECRET');
- $kid = env('JWT_KID');
- try {
- $key = new Key($jwtSecret, 'HS256');
- $headers = null;
- $decoded = JWT::decode($refreshToken, $key, $headers);
- if ($decoded->exp < time()) {
- return $this->fail('리프레시 토큰이 만료되었습니다.', 401);
- }
- $userId = $decoded->sub ?? null;
- if (!$userId) {
- return $this->fail('유효하지 않은 토큰입니다.', 401);
- }
- // ADM_LIST에서 해당 유저와 REFRESH_TOKEN 비교
- $db = \Config\Database::connect();
- $builder = $db->table('ADM_LIST');
- $user = $builder->where('ID', $userId)->get()->getRowArray();
- if (!$user) {
- return $this->fail('사용자를 찾을 수 없습니다.', 404);
- }
- unset($user['PASSWORD']);
- // DB에 저장된 리프레시 토큰과 요청 리프레시 토큰이 일치하지 않으면 거절
- if (!isset($user['REFRESH_TOKEN']) || $user['REFRESH_TOKEN'] !== $refreshToken) {
- return $this->fail('리프레시 토큰 불일치 또는 무효한 요청입니다.', 401);
- }
- // 일치하면 액세스 토큰 발급
- $issuedAt = time();
- $expire = $issuedAt + 60 * 15; // 15분
- //$expire = $issuedAt + 5; // 15분
- $accessPayload = [
- 'iat' => $issuedAt,
- 'exp' => $expire,
- 'sub' => $userId,
- 'name' => $user['NAME'] ?? '',
- ];
- $accessToken = JWT::encode($accessPayload, $jwtSecret, 'HS256', $kid);
- return $this->respond([
- 'accessToken' => $accessToken,
- 'user' => $user,
- ]);
- } catch (\Throwable $e) {
- return $this->fail('유효하지 않은 리프레시 토큰입니다.', 401);
- }
- }
-
- }
|