From f44a82b46f4ce999d99b249633f1784351686a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A4=80=ED=9D=A0?= Date: Thu, 10 Oct 2024 15:21:27 +0900 Subject: [PATCH] cfmgrv4 init...2 --- app/Config/Filters.php | 4 +- app/Config/Routes.php | 2 +- .../Admin/Cloudflare/CloudflareController.php | 18 +- app/Controllers/Admin/UserController.php | 12 ++ app/Controllers/CommonController.php | 19 ++- app/Controllers/MVController.php | 66 +++----- app/Controllers/UserController.php | 44 ++--- app/Filters/AuthFilter.php | 26 +-- app/Helpers/CommonHelper.php | 4 +- app/Libraries/MyAuth/GoogleAuth.php | 52 +----- app/Libraries/MyAuth/LocalAuth.php | 1 + app/Libraries/MyAuth/MyAuth.php | 30 +++- app/Libraries/MySocket/GoogleSocket.php | 158 ++++++++++++------ app/Libraries/MySocket/GoogleSocketAPI.php | 88 ++++++++++ app/Views/admin/login.php | 28 ---- app/Views/front/login.php | 7 +- app/Views/layouts/admin.php | 3 +- app/Views/layouts/empty.php | 5 +- app/Views/layouts/front.php | 1 + app/Views/templates/admin/index_footer.php | 1 - app/Views/templates/front/index_footer.php | 1 - public/css/admin.css | 1 - public/css/empty.css | 1 - public/css/front.css | 1 - 24 files changed, 337 insertions(+), 236 deletions(-) create mode 100644 app/Libraries/MySocket/GoogleSocketAPI.php delete mode 100644 app/Views/admin/login.php diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 046d0f7..f101cce 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -2,6 +2,7 @@ namespace Config; +use App\Filters\AuthFilter; use CodeIgniter\Config\Filters as BaseFilters; use CodeIgniter\Filters\Cors; use CodeIgniter\Filters\CSRF; @@ -12,7 +13,6 @@ use CodeIgniter\Filters\InvalidChars; use CodeIgniter\Filters\PageCache; use CodeIgniter\Filters\PerformanceMetrics; use CodeIgniter\Filters\SecureHeaders; -use App\Filters\AuthFilter; class Filters extends BaseFilters { @@ -35,7 +35,7 @@ class Filters extends BaseFilters 'forcehttps' => ForceHTTPS::class, 'pagecache' => PageCache::class, 'performance' => PerformanceMetrics::class, - 'authFilter' => AuthFilter::class, + 'authFilter' => AuthFilter::class, ]; /** diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 26c7a74..f4f5994 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -16,7 +16,7 @@ $routes->group('/user', function ($routes) { $routes->get('login', 'UserController::login_form'); $routes->post('login', 'UserController::login'); $routes->get('google_login', 'UserController::google_login'); - $routes->get('logout', 'UserController::logout', ['filter' => 'authFilter:user']); + $routes->get('logout', 'UserController::logout'); }); $routes->group('cli', ['namespace' => 'App\CLI'], function ($routes) { $routes->group('cloudflare', ['namespace' => 'App\CLI\Cloudflare'], function ($routes) { diff --git a/app/Controllers/Admin/Cloudflare/CloudflareController.php b/app/Controllers/Admin/Cloudflare/CloudflareController.php index 3b7c747..4f2b516 100644 --- a/app/Controllers/Admin/Cloudflare/CloudflareController.php +++ b/app/Controllers/Admin/Cloudflare/CloudflareController.php @@ -61,15 +61,14 @@ abstract class CloudflareController extends AdminController $this->sync_process($uid); $this->message = "{$this->class_name}: 동기화작업을 완료하였습니다."; $this->getModel()->transCommit(); - log_message("notice", $this->message); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], $this->message); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + log_message("notice", __FUNCTION__ . $this->message); + // 이전 URL로 리다이렉트 + return redirect()->to($this->popPreviousUrl())->with('error', $this->message); } catch (\Exception $e) { //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } @@ -82,15 +81,14 @@ abstract class CloudflareController extends AdminController $this->reload_process($uid); $this->message = "{$this->class_name}: Reload 작업이 완료되었습니다."; $this->getModel()->transCommit(); - log_message("notice", $this->message); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], $this->message); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + log_message("notice", __FUNCTION__ . $this->message); + // 이전 URL로 리다이렉트 + return redirect()->to($this->popPreviousUrl())->with('error', $this->message); } catch (\Exception $e) { //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } } diff --git a/app/Controllers/Admin/UserController.php b/app/Controllers/Admin/UserController.php index 983a366..460ec22 100644 --- a/app/Controllers/Admin/UserController.php +++ b/app/Controllers/Admin/UserController.php @@ -62,6 +62,18 @@ class UserController extends AdminController } $formDatas[$field] = implode(DEFAULTS["DELIMITER_ROLE"], $roles); break; + case 'passwd': //데이터가 있을때면 formData에 넣어줌 : 수정시에는 않넣을수도 있어야하므로 + $passwd = $this->request->getVar($field); + if ($passwd) { + $formDatas[$field] = $passwd; + } + break; + case 'confirmpassword': + $confirmpassword = $this->request->getVar($field); + if ($confirmpassword) { + $formDatas[$field] = $confirmpassword; + } + break; default: $formDatas = parent::getFormData($field, $formDatas); break; diff --git a/app/Controllers/CommonController.php b/app/Controllers/CommonController.php index 154f852..a850b55 100644 --- a/app/Controllers/CommonController.php +++ b/app/Controllers/CommonController.php @@ -13,7 +13,8 @@ abstract class CommonController extends BaseController public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) { parent::initController($request, $response, $logger); - $this->session = service('session'); + // 세션 서비스 초기화 + $this->session = \Config\Services::session(); } final public function __get($name) { @@ -30,4 +31,20 @@ abstract class CommonController extends BaseController { return $this->_viewDatas; } + + final protected function pushCurrentUrl() + { + $urlStack = $this->session->get('url_stack', []) ?? []; + $urlStack[] = current_url() . ($this->request->getUri()->getQuery() ? "?" . $this->request->getUri()->getQuery() : ""); + $this->session->set('url_stack', $urlStack); + } + + final protected function popPreviousUrl() + { + $urlStack = $this->session->get('url_stack', []); + if (!empty($urlStack)) { + return array_pop($urlStack); + } + return '/'; // 기본 URL + } } diff --git a/app/Controllers/MVController.php b/app/Controllers/MVController.php index a9ed62e..83811cc 100644 --- a/app/Controllers/MVController.php +++ b/app/Controllers/MVController.php @@ -17,7 +17,6 @@ abstract class MVController extends CommonController public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) { parent::initController($request, $response, $logger); - $this->session = service('session'); $this->class_path = ""; } abstract protected function getModel(): mixed; @@ -95,7 +94,6 @@ abstract class MVController extends CommonController try { helper(['form']); $this->create_form_process(); - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); $this->forms = ['attributes' => ['method' => "post",], 'hiddens' => []]; return view( $this->view_path . "create", @@ -103,7 +101,7 @@ abstract class MVController extends CommonController ); } catch (\Exception $e) { log_message("error", $e->getMessage()); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with(SESSION_NAMES['RETURN_MSG'], $e->getMessage()); + return redirect()->back()->with('error', $e->getMessage()); } } protected function create_process(): void @@ -119,9 +117,8 @@ abstract class MVController extends CommonController try { helper(['form']); $this->create_process(); - $this->message = "{$this->class_name} : 생성작업이 완료되었습니다."; $this->getModel()->transCommit(); - log_message("notice", __FUNCTION__ . $this->message); + $this->message = "{$this->class_name} : 생성작업이 완료되었습니다."; return view( $this->view_path . "view", data: ['viewDatas' => $this->getViewDatas()] @@ -130,9 +127,7 @@ abstract class MVController extends CommonController //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); - return redirect()->back()->withInput(); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } // 수정 @@ -159,7 +154,6 @@ abstract class MVController extends CommonController try { helper(['form']); $this->modify_form_process($uid); - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); $this->forms = ['attributes' => ['method' => "post",], 'hiddens' => []]; return view( $this->view_path . "modify", @@ -167,7 +161,7 @@ abstract class MVController extends CommonController ); } catch (\Exception $e) { log_message("error", $e->getMessage()); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with(SESSION_NAMES['RETURN_MSG'], $e->getMessage()); + return redirect()->back()->with('error', $e->getMessage()); } } protected function modify_process(string $uid): void @@ -188,9 +182,8 @@ abstract class MVController extends CommonController try { helper(['form']); $this->modify_process($uid); - $this->message = "{$this->class_name} : 생성작업이 완료되었습니다."; $this->getModel()->transCommit(); - log_message("notice", __FUNCTION__ . $this->message); + $this->message = "{$this->class_name} : 수정작업이 완료되었습니다."; return view( $this->view_path . "view", data: ['viewDatas' => $this->getViewDatas()] @@ -199,9 +192,7 @@ abstract class MVController extends CommonController //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); - return redirect()->back()->withInput(); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } //일괄처리작업 @@ -219,17 +210,14 @@ abstract class MVController extends CommonController $this->modify_process($uid); } $this->message = "{$this->class_name} : 일괄처리작업이 완료되었습니다."; - $this->getModel()->transCommit(); - log_message("notice", $this->message); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], $this->message); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + log_message("notice", __FUNCTION__ . $this->message); + // 이전 URL로 리다이렉트 + return redirect()->to($this->popPreviousUrl())->with('error', $this->message); } catch (\Exception $e) { //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); - return redirect()->back()->withInput(); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } //단일필드작업 @@ -243,15 +231,14 @@ abstract class MVController extends CommonController $this->modify_process($uid); $this->message = "{$this->class_name} : Toggle 수정작업이 완료되었습니다."; $this->getModel()->transCommit(); - log_message("notice", $this->message); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], $this->message); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + log_message("notice", __FUNCTION__ . $this->message); + // 이전 URL로 리다이렉트 + return redirect()->to($this->popPreviousUrl())->with('error', $this->message); } catch (\Exception $e) { //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); - return redirect()->back()->withInput(); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } //삭제 @@ -272,16 +259,14 @@ abstract class MVController extends CommonController $this->delete_process($uid); $this->message = "{$this->class_name} : 삭제작업이 완료되었습니다."; $this->getModel()->transCommit(); - log_message("notice", $this->message); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], $this->message); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + log_message("notice", __FUNCTION__ . $this->message); + // 이전 URL로 리다이렉트 + return redirect()->to($this->popPreviousUrl())->with('error', $this->message); } catch (\Exception $e) { //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); - return redirect()->back()->withInput(); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } // 리스트 @@ -361,7 +346,7 @@ abstract class MVController extends CommonController log_message("debug", $this->getModel()->getLastQuery()); return $entitys; } - final protected function list_procedure(): string + final protected function list_procedure(): RedirectResponse|string { try { helper(['form']); @@ -373,9 +358,9 @@ abstract class MVController extends CommonController $this->pagination = $this->list_pagination_process(); //모델 처리 $this->entitys = $this->list_entitys_process(); - //setting return_url to session flashdata - // RETURN_URL을 일반 세션 데이터로 저장 - $this->session->setFlashdata(SESSION_NAMES['RETURN_URL'], current_url() . ($this->uri->getQuery() ? "?" . $this->uri->getQuery() : "")); + + // 현재 URL을 스택에 저장 + $this->pushCurrentUrl(); return view( $this->view_path . "index", @@ -383,8 +368,7 @@ abstract class MVController extends CommonController ); } catch (\Exception $e) { log_message("error", $e->getMessage()); - return $this->helper->alert($e->getMessage(), "back"); - // return redirect()->back()->with(SESSION_NAMES['RETURN_MSG'], $e->getMessage()); + return redirect()->back()->with('error', $e->getMessage()); } } @@ -420,7 +404,7 @@ abstract class MVController extends CommonController return array($full_path, $file_name); } //File Download관련 - final protected function download_procedure(string $output_type, $uid = false): DownloadResponse|string + final protected function download_procedure(string $output_type, $uid = false): DownloadResponse|RedirectResponse { try { helper(['form']); @@ -456,7 +440,7 @@ abstract class MVController extends CommonController return $this->response->download($full_path, null)->setFileName($file_name); } catch (\Exception $e) { log_message("error", $e->getMessage()); - return $this->helper->alert($e->getMessage(), "back"); + return redirect()->back()->with('error', $e->getMessage()); } } } diff --git a/app/Controllers/UserController.php b/app/Controllers/UserController.php index 6ced88d..042a984 100644 --- a/app/Controllers/UserController.php +++ b/app/Controllers/UserController.php @@ -12,7 +12,6 @@ use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\Validation\Validation; -use Google\Service\Oauth2; use Psr\Log\LoggerInterface; class UserController extends FrontController @@ -89,8 +88,6 @@ class UserController extends FrontController //구글 로그인 BUTTON용 $google_socket = new GoogleSocket(); $this->google_url = $google_socket->createAuthUrl(); - - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); $this->forms = ['attributes' => ['method' => "post",], 'hiddens' => []]; return view( $this->view_path . "login", @@ -98,7 +95,7 @@ class UserController extends FrontController ); } catch (\Exception $e) { log_message("error", $e->getMessage()); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/")->with(SESSION_NAMES['RETURN_MSG'], $e->getMessage()); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } //로그인처리 @@ -111,19 +108,17 @@ class UserController extends FrontController $this->create_validate($this->action, $this->fields); $this->formDatas = $this->getFormDatas(); $auth = new LocalAuth(); - $auth->setLogin($auth->checkUser($this->formDatas)); + $auth->login($auth->checkUser($this->formDatas)); $this->message = "로그인 성공"; $this->getModel()->transCommit(); - log_message("notice", $this->message); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], $this->message); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + log_message("notice", __FUNCTION__ . $this->message); + // 이전 URL로 리다이렉트 + return redirect()->to($this->popPreviousUrl())->with('message', $this->message); } catch (\Exception $e) { //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], "로그인 실패하였습니다.\n" . $e->getMessage()); - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); - return redirect()->back()->withInput(); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } public function google_login(): RedirectResponse|string @@ -137,27 +132,32 @@ class UserController extends FrontController throw new \Exception("구글 로그인 실패"); } $auth = new GoogleAuth($access_code); - $auth->setLogin($auth->checkUser()); + $auth->login($auth->checkUser()); $this->message = "로그인 성공"; $this->getModel()->transCommit(); - log_message("notice", $this->message); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], $this->message); - return redirect()->to($this->session->getFlashdata(SESSION_NAMES['RETURN_URL']) ?: "/"); + log_message("notice", __FUNCTION__ . $this->message); + // 이전 URL로 리다이렉트 + return redirect()->to($this->popPreviousUrl())->with('message', $this->message); } catch (\Exception $e) { //Transaction Rollback $this->getModel()->transRollback(); log_message("error", $e->getMessage()); - $this->session->setFlashdata(SESSION_NAMES['RETURN_MSG'], "로그인 실패하였습니다.\n" . $e->getMessage()); - $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); - return redirect()->back()->withInput(); + return redirect()->back()->withInput()->with('error', __FUNCTION__ . " 실패하였습니다.\n" . $e->getMessage()); } } //로그아웃 public function logout(): RedirectResponse { - //Session에 Login 정보 삭제 - session()->set([SESSION_NAMES['ISLOGIN'] => false]); - session_destroy(); - return redirect()->route('/'); + try { + $auth = new LocalAuth(); + $auth->logout(); + // 성공 메시지 설정 + $message = "로그아웃 되었습니다."; + // 홈페이지로 리다이렉트 + return redirect()->route('/')->with('message', $message); + } catch (\Exception $e) { + log_message("error", $e->getMessage()); + return redirect()->back()->with('error', "로그아웃 중 오류가 발생했습니다."); + } } } diff --git a/app/Filters/AuthFilter.php b/app/Filters/AuthFilter.php index 8826c34..c392a76 100644 --- a/app/Filters/AuthFilter.php +++ b/app/Filters/AuthFilter.php @@ -25,24 +25,14 @@ class AuthFilter implements FilterInterface */ public function before(RequestInterface $request, $arguments = null) { - // 로그인을 했으면 - if (session()->get(SESSION_NAMES['ISLOGIN'])) { - $auth = session()->get(SESSION_NAMES['AUTH']); - // 회원 ROLES이 필요ROLE($arguments[0]) 목록에 존재하지 않으면(ACL) - if (!in_array($arguments[0], explode(DEFAULTS['DELIMITER_ROLE'], $auth['role']))) { - return redirect()->to(URLS['LOGIN'])->with( - 'return_message', - sprintf( - "%s,%s회원님은 접속에 필요한 권한[%s]이 없습니다. ", - $auth['role'], - $auth['name'], - implode(",", $arguments) - ) - ); - } - } else { - session()->setFlashdata(SESSION_NAMES['RETURN_URL'], $request->getUri()->getPath() . '?' . $request->getUri()->getQuery()); - return redirect()->to(URLS['LOGIN'])->with('return_message', '로그인을하셔야합니다.'); + // 로그인 않했으면 + if (!session()->has(SESSION_NAMES['ISLOGIN'])) { + return redirect()->to(URLS['LOGIN'])->with('error', '로그인을하셔야합니다.'); + } + //User Role 비교 // 회원 ROLES이 필요ROLE($arguments[0]) 목록에 존재하지 않으면(ACL) + $auth = session()->get(SESSION_NAMES['AUTH']); + if (!isset($auth['role']) || !in_array($arguments[0], explode(DEFAULTS['DELIMITER_ROLE'], $auth['role']))) { + return redirect()->back()->with('error', "회원[{$auth['name']}]님은 접속에 필요한 권한이 없습니다. "); } } diff --git a/app/Helpers/CommonHelper.php b/app/Helpers/CommonHelper.php index 19cb17a..c13ca31 100644 --- a/app/Helpers/CommonHelper.php +++ b/app/Helpers/CommonHelper.php @@ -221,7 +221,7 @@ abstract class CommonHelper $extras = ["class" => "btn btn-outline btn-primary btn-circle", "target" => "_self", ...$extras]; $action = form_label( '입력', - "", + $action, [ "data-src" => current_url() . '/' . $action, "data-bs-toggle" => "modal", @@ -243,7 +243,7 @@ abstract class CommonHelper ]); $action = $checkbox . form_label( $viewDatas['cnt'], - "", + $action, [ "data-src" => current_url() . '/' . $action . '/' . $viewDatas['entity']->getPK(), "data-bs-toggle" => "modal", diff --git a/app/Libraries/MyAuth/GoogleAuth.php b/app/Libraries/MyAuth/GoogleAuth.php index 9df8c90..3db90ed 100644 --- a/app/Libraries/MyAuth/GoogleAuth.php +++ b/app/Libraries/MyAuth/GoogleAuth.php @@ -38,58 +38,22 @@ class GoogleAuth extends MyAuth return $this->_model; } - // throw new \Exception(__METHOD__ . "에서 데이터 처리 필요"); - // DEBUG - 2023-07-13 12:54:51 --> \Google\Service\Oauth2\Userinfo::__set_state(array( - // 'internal_gapi_mappings' => - // 'familyName' => 'family_name', - // 'givenName' => 'given_name', - // 'verifiedEmail' => 'verified_email', - // ), - // 'modelData' => - // array ( - // 'verified_email' => true, - // 'given_name' => '이름', - // 'family_name' => '성', - // ), - // 'processed' => - // array ( - // ), - // 'email' => 'twsdfsew342s@gmail.com', - // 'familyName' => '성', - // 'gender' => NULL, - // 'givenName' => '이름', - // 'hd' => NULL, - // 'id' => '103667492432234234236838324', - // 'link' => NULL, - // 'locale' => 'ko', - // 'name' => '성이름', - // 'picture' => 'https://lh3.googleusercontent.com/a/AAcHTteFSgefsdfsdRJBkJA2tBEmg4PQrvI1Ta_5IXu5=s96-c', - // 'verifiedEmail' => true, - // )) public function checkUser(): UserEntity { try { // Google 서비스 설정 - $service = new Oauth2($this->getMySocket()); - // 액세스 토큰 유효성 검사 추가 - if (!$this->getMySocket()->isAccessTokenValid()) { - $this->getMySocket()->refreshToken($this->getMySocket()->getRefreshToken()); - } - - $authInfo = $service->userinfo->get(); - log_message('debug', var_export($authInfo, true)); - + $userInfo = $this->getMySocket()->getUserInfo(); //기존 등록된 사용자가 있는지 검사 $this->getModel()->where(UserSNSModel::SITE, $this->_site); - $entity = $this->getModel()->getEntityByID($authInfo['id']); + $entity = $this->getModel()->getEntityByID($userInfo['id']); if ($entity === null) { //없다면 새로 등록 $formDatas = [ 'site' => $this->_site, - 'id' => $authInfo['id'], - 'name' => $authInfo['name'], - 'email' => $authInfo['email'], - 'detail' => json_encode($authInfo), + 'id' => $userInfo['id'], + 'name' => $userInfo['name'], + 'email' => $userInfo['email'], + 'detail' => var_export($userInfo, true), 'status' => 'standby', ]; $entity = $this->getModel()->create($formDatas); @@ -98,13 +62,13 @@ class GoogleAuth extends MyAuth if ( $entity->status !== DEFAULTS['STATUS'] ) { - throw new PageNotFoundException("{$this->_site}}의{$authInfo['email']}:{$authInfo['name']}님은 " . $entity->status . "입니다"); + throw new PageNotFoundException("{$this->_site}}의{$userInfo['email']}:{$userInfo['name']}님은 " . $entity->status . "입니다"); } //local db 사용와의 연결 확인 $userModel = model(UserModel::class); $user_entity = $userModel->getEntityByID($entity->getID()); if ($user_entity === null) { - throw new PageNotFoundException("{$this->_site}의{$authInfo['email']}:{$authInfo['name']}님은 아직 사용자 연결이 이루어지지 않았습니다. "); + throw new PageNotFoundException("{$this->_site}의{$userInfo['email']}:{$userInfo['name']}님은 아직 사용자 연결이 이루어지지 않았습니다. "); } return $user_entity; } catch (\Google_Service_Exception $e) { diff --git a/app/Libraries/MyAuth/LocalAuth.php b/app/Libraries/MyAuth/LocalAuth.php index 3d13a3f..2d018b2 100644 --- a/app/Libraries/MyAuth/LocalAuth.php +++ b/app/Libraries/MyAuth/LocalAuth.php @@ -34,6 +34,7 @@ class LocalAuth extends MyAuth throw new \Exception("사용자ID: {$formDatas['id']}가 존재하지 않습니다."); } if (!password_verify($formDatas['passwd'], $entity->passwd)) { + // log_message("error", "암호: {$formDatas['passwd']}, {$entity->passwd}"); throw new \Exception("암호가 맞지 않습니다."); } return $entity; diff --git a/app/Libraries/MyAuth/MyAuth.php b/app/Libraries/MyAuth/MyAuth.php index 72d1fbe..54f2ab6 100644 --- a/app/Libraries/MyAuth/MyAuth.php +++ b/app/Libraries/MyAuth/MyAuth.php @@ -14,7 +14,7 @@ abstract class MyAuth extends CommonLibrary $this->_session = \Config\Services::session(); } - final public function setLogin(UserEntity $entity): void + final public function login(UserEntity $entity): void { $this->_session->set(SESSION_NAMES['ISLOGIN'], true); $this->_session->set(SESSION_NAMES['AUTH'], [ @@ -23,4 +23,32 @@ abstract class MyAuth extends CommonLibrary 'role' => $entity->role ]); } + + final public function logout(): void + { + // 세션 데이터 삭제 + $this->_session->remove(SESSION_NAMES['ISLOGIN']); + $this->_session->remove(SESSION_NAMES['AUTH']); + + // 모든 세션 데이터 삭제 + $this->_session->destroy(); + + // 세션 쿠키 삭제 + if (ini_get("session.use_cookies")) { + $params = session_get_cookie_params(); + setcookie( + session_name(), + '', + time() - 42000, + $params["path"], + $params["domain"], + $params["secure"], + $params["httponly"] + ); + } + + // 세션 재생성 + session_start(); + $this->_session->regenerate(true); + } } diff --git a/app/Libraries/MySocket/GoogleSocket.php b/app/Libraries/MySocket/GoogleSocket.php index 2d5cd1b..0529157 100644 --- a/app/Libraries/MySocket/GoogleSocket.php +++ b/app/Libraries/MySocket/GoogleSocket.php @@ -3,47 +3,76 @@ namespace App\Libraries\MySocket; use CodeIgniter\Config\Services; -use CodeIgniter\Exceptions\ConfigException; -use Google\Client; -use Google\Service\Oauth2; -class GoogleSocket extends Client +class GoogleSocket extends MySocket { private $session; private string $_access_token = ""; private string $_token_name = "access_token"; + private string $_token_type = ""; + private string $_google_oauth_version = "v3"; public function __construct() { parent::__construct(); - $this->setClientId(env('socket.google.client.id')); - $this->setClientSecret(env('socket.google.client.key')); - $this->setRedirectUri(base_url(env('socket.google.client.callback_url'))); - $this->addScope(Oauth2::USERINFO_EMAIL); - $this->addScope(Oauth2::USERINFO_PROFILE); - // $this->setPrompt('select_account consent'); - // $this->setAccessType('offline'); - // SSL 검증 비활성화 - $this->setHttpClient(new \GuzzleHttp\Client(['verify' => false])); - // 사용자 정의 CA 번들 사용 - // $this->setHttpClient(new \GuzzleHttp\Client(['verify' => '/path/to/cacert.pem'])); $this->session = Services::session(); } + public function createAuthUrl(): string + { + $options = http_build_query([ + 'response_type' => 'code', + 'client_id' => env('socket.google.client.id'), + 'redirect_uri' => base_url(env('socket.google.client.callback_url')), + 'scope' => "https://www.googleapis.com/auth/userinfo.profile openid https://www.googleapis.com/auth/userinfo.email", + 'access_type' => 'offline', + 'prompt' => 'consent' + ]); + //기본적으로 검색할 범위를 지정하고 사용자를 Google OAuth 동의 화면으로 리디렉션합니다 + return "https://accounts.google.com/o/oauth2/v2/auth?" . $options; + } + + // (object) array( + // 'access_token' => 'sdfsdfsdfsdf', + // 'expires_in' => 3599, + // 'refresh_token' => 'sdfsdf', + // 'scope' => 'https://www.googleapis.com/auth/userinfo.profile openid https://www.googleapis.com/auth/userinfo.email', + // 'token_type' => 'Bearer', + // 'id_token' => 'fadfasdfsadf', + // ) public function setToken(string $access_code): void { - // 토큰 정보 가져오기 - $tokenInfo = $this->fetchAccessTokenWithAuthCode($access_code); + $options = [ + 'code' => $access_code, + 'client_id' => env('socket.google.client.id'), + 'client_secret' => env('socket.google.client.key'), + 'redirect_uri' => base_url(env('socket.google.client.callback_url')), + 'grant_type' => 'authorization_code', + ]; + $response = $this->post("https://accounts.google.com/o/oauth2/token", $options); + $tokenInfo = json_decode($response->getBody(), true); if (isset($tokenInfo['error'])) { - throw new ConfigException($tokenInfo['error']); + $message = sprintf( + "Google: %s에서 API 호출 실패: \n--request options--\n%s\n--response--\n%s\n", + __FUNCTION__, + var_export($options, true), + var_export($response, true) + ); + log_message("error", $message); + throw new \Exception($message); } - // dd($tokenInfo); + if (!isset($tokenInfo[$this->_token_name]) || empty($tokenInfo[$this->_token_name])) { + $message = sprintf( + "Google: Token 정보가 없습니다.\n--tokenInfo--\n%s\n", + __FUNCTION__, + var_export($tokenInfo, true) + ); + log_message("error", $message); + throw new \Exception($message); + } + //토큰 Type정보 가져오기 getUserInfo()에서 사용 + $this->_token_type = $tokenInfo['token_type']; + // 토큰 정보 가져오기 $this->_access_token = $tokenInfo[$this->_token_name]; - // Google Service에 접근하기 위해 Access Token 설정 - $this->setAccessToken([ - 'access_token' => $this->_access_token, - 'expires_in' => 3600, - 'created' => time(), - ]); // 세션에 Token 값 설정 $this->session->set($this->_token_name, $this->_access_token); } @@ -53,36 +82,59 @@ class GoogleSocket extends Client return $this->session->get($this->_token_name); } - public function isAccessTokenValid(): bool + // throw new \Exception(__METHOD__ . "에서 데이터 처리 필요"); + // DEBUG - 2023-07-13 12:54:51 --> \Google\Service\Oauth2\Userinfo::__set_state(array( + // 'internal_gapi_mappings' => + // 'familyName' => 'family_name', + // 'givenName' => 'given_name', + // 'verifiedEmail' => 'verified_email', + // ), + // 'modelData' => + // array ( + // 'verified_email' => true, + // 'given_name' => '이름', + // 'family_name' => '성', + // ), + // 'processed' => + // array ( + // ), + // 'email' => 'twsdfsew342s@gmail.com', + // 'familyName' => '성', + // 'gender' => NULL, + // 'givenName' => '이름', + // 'hd' => NULL, + // 'id' => '103667492432234234236838324', + // 'link' => NULL, + // 'locale' => 'ko', + // 'name' => '성이름', + // 'picture' => 'https://lh3.googleusercontent.com/a/AAcHTteFSgefsdfsdRJBkJA2tBEmg4PQrvI1Ta_5IXu5=s96-c', + // 'verifiedEmail' => true, + // )) + public function getUserInfo(): array { - // 액세스 토큰이 없으면 유효하지 않음 - if (empty($this->getAccessToken())) { - return false; + $options = ["Authorization: {$this->_token_type} {$this->getToken()}"]; + $response = $this->get("https://www.googleapis.com/oauth2/{$this->_google_oauth_version}/userinfo", $options); + $userInfo = json_decode($response->getBody(), true); + if (isset($userInfo['error'])) { + $message = sprintf( + "Google: %s에서 API 호출 실패: \n--request options--\n%s\n--response--\n%s\n", + __FUNCTION__, + var_export($options, true), + var_export($response, true) + ); + log_message("error", $message); + throw new \Exception($message); } - - // 토큰의 만료 시간 확인 - $expirationTime = $this->getTokenExpirationTime(); - if ($expirationTime === null) { - return false; + if (isset($userInfo['email']) || empty($tokenInfo['email'])) { + $message = sprintf( + "Google: User 정보가 없습니다.\n--userInfo--\n%s\n", + __FUNCTION__, + var_export($userInfo, true) + ); + log_message("error", $message); + throw new \Exception($message); } - - // 현재 시간과 비교하여 유효성 확인 - return $expirationTime > time(); - } - - private function getTokenExpirationTime(): ?int - { - // 토큰 정보 디코딩 - $tokenParts = explode('.', $this->getToken()); - if (count($tokenParts) !== 3) { - return null; - } - - $payload = json_decode(base64_decode($tokenParts[1]), true); - if (!isset($payload['exp'])) { - return null; - } - - return $payload['exp']; + // 사용자정보 가져오기 + return $userInfo; } } diff --git a/app/Libraries/MySocket/GoogleSocketAPI.php b/app/Libraries/MySocket/GoogleSocketAPI.php new file mode 100644 index 0000000..e3100e2 --- /dev/null +++ b/app/Libraries/MySocket/GoogleSocketAPI.php @@ -0,0 +1,88 @@ +setClientId(env('socket.google.client.id')); + $this->setClientSecret(env('socket.google.client.key')); + $this->setRedirectUri(base_url(env('socket.google.client.callback_url'))); + $this->addScope(Oauth2::USERINFO_EMAIL); + $this->addScope(Oauth2::USERINFO_PROFILE); + // $this->setPrompt('select_account consent'); + // $this->setAccessType('offline'); + // SSL 검증 비활성화 + $this->setHttpClient(new \GuzzleHttp\Client(['verify' => false])); + // 사용자 정의 CA 번들 사용 + // $this->setHttpClient(new \GuzzleHttp\Client(['verify' => '/path/to/cacert.pem'])); + $this->session = Services::session(); + } + + public function setToken(string $access_code): void + { + // 토큰 정보 가져오기 + $tokenInfo = $this->fetchAccessTokenWithAuthCode($access_code); + if (isset($tokenInfo['error'])) { + throw new ConfigException($tokenInfo['error']); + } + // dd($tokenInfo); + $this->_access_token = $tokenInfo[$this->_token_name]; + // Google Service에 접근하기 위해 Access Token 설정 + $this->setAccessToken([ + 'access_token' => $this->_access_token, + 'expires_in' => 3600, + 'created' => time(), + ]); + // 세션에 Token 값 설정 + $this->session->set($this->_token_name, $this->_access_token); + } + + public function getToken(): string + { + return $this->session->get($this->_token_name); + } + + public function isAccessTokenValid(): bool + { + // 액세스 토큰이 없으면 유효하지 않음 + if (empty($this->getAccessToken())) { + return false; + } + + // 토큰의 만료 시간 확인 + $expirationTime = $this->getTokenExpirationTime(); + if ($expirationTime === null) { + return false; + } + + // 현재 시간과 비교하여 유효성 확인 + return $expirationTime > time(); + } + + private function getTokenExpirationTime(): ?int + { + // 토큰 정보 디코딩 + $tokenParts = explode('.', $this->getToken()); + if (count($tokenParts) !== 3) { + return null; + } + + $payload = json_decode(base64_decode($tokenParts[1]), true); + if (!isset($payload['exp'])) { + return null; + } + + return $payload['exp']; + } +} diff --git a/app/Views/admin/login.php b/app/Views/admin/login.php deleted file mode 100644 index 7ee44d9..0000000 --- a/app/Views/admin/login.php +++ /dev/null @@ -1,28 +0,0 @@ -extend(LAYOUTS[$viewDatas['layout']]['path']) ?> -section('content') ?> -
-
-
- - -
-
-
-endSection() ?> \ No newline at end of file diff --git a/app/Views/front/login.php b/app/Views/front/login.php index 7ee44d9..f77b94d 100644 --- a/app/Views/front/login.php +++ b/app/Views/front/login.php @@ -6,7 +6,7 @@
-

로그인

+

CF-MGR 로그인

@@ -16,7 +16,7 @@
- + "btn btn-danger"]) ?>
@@ -24,5 +24,4 @@
- -endSection() ?> \ No newline at end of file + endSection() ?> \ No newline at end of file diff --git a/app/Views/layouts/admin.php b/app/Views/layouts/admin.php index 8f7fc4b..21dbb89 100644 --- a/app/Views/layouts/admin.php +++ b/app/Views/layouts/admin.php @@ -23,7 +23,8 @@ - renderSection('content') ?> + alert($error) ?> + renderSection('content') ?> \ No newline at end of file diff --git a/app/Views/layouts/empty.php b/app/Views/layouts/empty.php index 6c37286..ce76d5b 100644 --- a/app/Views/layouts/empty.php +++ b/app/Views/layouts/empty.php @@ -23,9 +23,8 @@ -
- renderSection('content') ?> -
+ alert($error) ?> +
renderSection('content') ?>
\ No newline at end of file diff --git a/app/Views/layouts/front.php b/app/Views/layouts/front.php index 8f7fc4b..33be8ea 100644 --- a/app/Views/layouts/front.php +++ b/app/Views/layouts/front.php @@ -23,6 +23,7 @@ + alert($error) ?> renderSection('content') ?> diff --git a/app/Views/templates/admin/index_footer.php b/app/Views/templates/admin/index_footer.php index 794fceb..e69de29 100644 --- a/app/Views/templates/admin/index_footer.php +++ b/app/Views/templates/admin/index_footer.php @@ -1 +0,0 @@ -getFlashdata(SESSION_NAMES['RETURN_MSG']) ? $viewDatas['helper']->alert($viewDatas['session']->getFlashdata(SESSION_NAMES['RETURN_MSG'])) : "" ?> \ No newline at end of file diff --git a/app/Views/templates/front/index_footer.php b/app/Views/templates/front/index_footer.php index 7cdbd2f..e69de29 100644 --- a/app/Views/templates/front/index_footer.php +++ b/app/Views/templates/front/index_footer.php @@ -1 +0,0 @@ -getFlashdata(SESSION_NAMES['RETURN_MSG']) ? $viewDatas['helper']->alert($viewDatas['session']->getFlashdata(SESSION_NAMES['RETURN_MSG'])) : "" ?> \ No newline at end of file diff --git a/public/css/admin.css b/public/css/admin.css index 0d8392a..8d180e2 100644 --- a/public/css/admin.css +++ b/public/css/admin.css @@ -8,7 +8,6 @@ margin: 0px; padding: 0px; border: 0px; - /* font-size: 15px; */ } html, diff --git a/public/css/empty.css b/public/css/empty.css index c110333..1e4df2e 100644 --- a/public/css/empty.css +++ b/public/css/empty.css @@ -8,5 +8,4 @@ margin: 0px; padding: 0px; border: 0px; - /* font-size: 15px; */ } \ No newline at end of file diff --git a/public/css/front.css b/public/css/front.css index 7a128fe..52349d4 100644 --- a/public/css/front.css +++ b/public/css/front.css @@ -8,7 +8,6 @@ margin: 0px; padding: 0px; border: 0px; - /* font-size: 15px; */ } html,