From 4b3edf80f025c5f6c754e76372a72172f9597e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A4=80=ED=9D=A0?= Date: Wed, 9 Oct 2024 19:42:40 +0900 Subject: [PATCH] cfmgrv4 init...2 --- app/Config/Routes.php | 7 ++ app/Controllers/Admin/UserSNSController.php | 109 ++++++++++++++++++ app/Controllers/UserController.php | 23 ++-- .../{SNSUserEntity.php => UserSNSEntity.php} | 10 +- app/Helpers/UserSNSHelper.php | 36 ++++++ app/Language/en/UserSNS.php | 19 +++ app/Libraries/MyAuth/GoogleAuth.php | 27 +++-- app/Libraries/MySocket/GoogleSocket.php | 62 ++++++++-- .../{SNSUserModel.php => UserSNSModel.php} | 35 ++++-- 9 files changed, 280 insertions(+), 48 deletions(-) create mode 100644 app/Controllers/Admin/UserSNSController.php rename app/Entities/{SNSUserEntity.php => UserSNSEntity.php} (66%) create mode 100644 app/Helpers/UserSNSHelper.php create mode 100644 app/Language/en/UserSNS.php rename app/Models/{SNSUserModel.php => UserSNSModel.php} (58%) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index e661e4d..26c7a74 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -36,6 +36,13 @@ $routes->group('admin', ['namespace' => 'App\Controllers\Admin', 'filter' => 'au $routes->post('batchjob', 'UserController::batcjob'); $routes->get('download/(:alpha)', 'UserController::download/$1'); }); + $routes->group('usersns', function ($routes) { + $routes->get('/', 'UserSNSController::index'); + $routes->get('delete/(:num)', 'UserSNSController::delete/$1', ['filter' => 'authFilter:master']); + $routes->get('toggle/(:num)/(:any)', 'UserSNSController::toggle/$1/$2', ['filter' => 'authFilter:master']); + $routes->post('batchjob', 'UserSNSController::batcjob', ['filter' => 'authFilter:master']); + $routes->get('download/(:alpha)', 'UserSNSController::download/$1'); + }); $routes->group('mapurl', function ($routes) { $routes->get('/', 'MapurlController::index'); $routes->get('create', 'MapurlController::create_form'); diff --git a/app/Controllers/Admin/UserSNSController.php b/app/Controllers/Admin/UserSNSController.php new file mode 100644 index 0000000..4fa17b4 --- /dev/null +++ b/app/Controllers/Admin/UserSNSController.php @@ -0,0 +1,109 @@ +class_name = "UserSNS"; + $this->class_path .= $this->class_name; + $this->title = lang("{$this->class_path}.title"); + $this->helper = new UserSNSHelper(); + } + protected function getModel(): UserSNSModel + { + if ($this->_model === null) { + $this->_model = new UserSNSModel(); + } + return $this->_model; + } + protected function setFormFieldRule($field, Validation $validation, string $action): Validation + { + switch ($field) { + default: + $validation = parent::setFormFieldRule($field, $validation, $action); + break; + } + return $validation; + } + protected function getFormFieldOption(string $field, array $options = []): array + { + switch ($field) { + default: + $options = parent::getFormFieldOption($field, $options); + break; + } + return $options; + } + protected function getFormData(string $field, array $formDatas): array + { + switch ($field) { + default: + $formDatas = parent::getFormData($field, $formDatas); + break; + } + return $formDatas; + } + private function init(string $action): void + { + $this->action = $action; + $this->fields = ['site', 'id', $this->getModel()::TITLE, 'email']; + $this->field_rules = $this->getModel()->getFieldRules($this->action, $this->fields); + $this->filter_fields = ['status']; + $this->field_options = $this->getFormFieldOptions($this->filter_fields); + } + //수정 + public function modify_form(string $uid): RedirectResponse|string + { + $this->init('modify'); + return $this->modify_form_procedure($uid); + } + public function modify(string $uid): RedirectResponse|string + { + $this->init(__FUNCTION__); + return $this->modify_procedure($uid); + } + //일괄작업 + public function batcjob(): RedirectResponse + { + $this->action = __FUNCTION__; + $this->fields = ['status']; + $this->field_rules = $this->getModel()->getFieldRules($this->action, $this->fields); + return $this->batcjob_procedure(); + } + // 리스트 + public function index(): string + { + $this->action = __FUNCTION__; + $this->fields = ['site', 'id', $this->getModel()::TITLE, 'email', 'status']; + $this->field_rules = $this->getModel()->getFieldRules($this->action, $this->fields); + $this->filter_fields = ['status']; + $this->field_options = $this->getFormFieldOptions($this->filter_fields); + $this->batchjob_fields = ['status']; + return $this->list_procedure(); + } + // Download + public function download(string $output_type, $uid = false): DownloadResponse|string + { + $this->action = __FUNCTION__; + $this->fields = ['site', 'id', $this->getModel()::TITLE, 'email', 'status']; + $this->field_rules = $this->getModel()->getFieldRules($this->action, $this->fields); + $this->filter_fields = ['status']; + $this->field_options = $this->getFormFieldOptions($this->filter_fields); + $this->batchjob_fields = ['status']; + return $this->download_procedure($output_type, $uid); + } +} diff --git a/app/Controllers/UserController.php b/app/Controllers/UserController.php index 261f50c..6ced88d 100644 --- a/app/Controllers/UserController.php +++ b/app/Controllers/UserController.php @@ -5,10 +5,11 @@ namespace App\Controllers; use App\Helpers\UserHelper; use App\Libraries\MyAuth\GoogleAuth; use App\Libraries\MyAuth\LocalAuth; +use App\Libraries\MySocket\GoogleSocket; use App\Models\UserModel; use CodeIgniter\HTTP\RedirectResponse; -use CodeIgniter\HTTP\RequestInterface; +use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\Validation\Validation; use Google\Service\Oauth2; @@ -70,17 +71,7 @@ class UserController extends FrontController } return $formDatas; } - private function getGoogleAuthUrl() - { - $params = [ - 'client_id' => env('socket.google.client.id'), - 'redirect_uri' => env('socket.google.client.callback_url'), - 'response_type' => 'code', // 이 줄을 추가하세요 - 'scope' => Oauth2::USERINFO_EMAIL . " " . Oauth2::USERINFO_PROFILE, - 'state' => env('socket.google.client.token_name'), - ]; - return env('socket.google.api.uri') . '?' . http_build_query($params); - } + private function init(string $action): void { $this->action = $action; @@ -94,8 +85,12 @@ class UserController extends FrontController try { helper(['form']); $this->create_form_process(); + + //구글 로그인 BUTTON용 + $google_socket = new GoogleSocket(); + $this->google_url = $google_socket->createAuthUrl(); + $this->session->keepFlashdata(SESSION_NAMES['RETURN_URL']); - $this->google_url = $this->getGoogleAuthUrl(); $this->forms = ['attributes' => ['method' => "post",], 'hiddens' => []]; return view( $this->view_path . "login", @@ -141,7 +136,7 @@ class UserController extends FrontController if (!$access_code) { throw new \Exception("구글 로그인 실패"); } - $auth = new GoogleAuth(env('socket.google.client.token_name'), $access_code); + $auth = new GoogleAuth($access_code); $auth->setLogin($auth->checkUser()); $this->message = "로그인 성공"; $this->getModel()->transCommit(); diff --git a/app/Entities/SNSUserEntity.php b/app/Entities/UserSNSEntity.php similarity index 66% rename from app/Entities/SNSUserEntity.php rename to app/Entities/UserSNSEntity.php index 511ca1c..1470baa 100644 --- a/app/Entities/SNSUserEntity.php +++ b/app/Entities/UserSNSEntity.php @@ -3,9 +3,9 @@ namespace App\Entities; use App\Entities\CommonEntity; -use App\Models\SNSUserModel; +use App\Models\UserSNSModel; -class SNSUserEntity extends CommonEntity +class UserSNSEntity extends CommonEntity { public function __toString(): string { @@ -13,17 +13,17 @@ class SNSUserEntity extends CommonEntity } public function getTitle(): string { - return $this->attributes[SNSUserModel::TITLE]; + return $this->attributes[UserSNSModel::TITLE]; } public function setTitle(string $title): void { - $this->attributes[SNSUserModel::TITLE] = $title; + $this->attributes[UserSNSModel::TITLE] = $title; } //Common Function public function getPK(): int { - return $this->attributes[SNSUserModel::PK]; + return $this->attributes[UserSNSModel::PK]; } public function getID(): string { diff --git a/app/Helpers/UserSNSHelper.php b/app/Helpers/UserSNSHelper.php new file mode 100644 index 0000000..99b89c5 --- /dev/null +++ b/app/Helpers/UserSNSHelper.php @@ -0,0 +1,36 @@ + "예)test@example.com", ...$extras]); + break; + case 'detail': + $form = form_textarea($field, $value == DEFAULTS['EMPTY'] ? "@\n*\nm\nwww" : $value, [ + 'rows' => '20', + ...$extras + ]); + break; + default: + $form = parent::getFieldForm($field, $value, $viewDatas, $extras); + break; + } + return $form; + } // +} diff --git a/app/Language/en/UserSNS.php b/app/Language/en/UserSNS.php new file mode 100644 index 0000000..d391750 --- /dev/null +++ b/app/Language/en/UserSNS.php @@ -0,0 +1,19 @@ + "SNS 계정정보", + 'label' => [ + 'uid' => "번호", + 'site' => "사이트", + 'id' => "계정", + 'name' => "이름", + 'email' => "메일", + 'detail' => "상세정보", + 'status' => "상태", + 'updated_at' => "수정일", + 'created_at' => "작성일", + ], + "STATUS" => [ + "use" => "사용", + "unuse" => "사용않함", + ], +]; diff --git a/app/Libraries/MyAuth/GoogleAuth.php b/app/Libraries/MyAuth/GoogleAuth.php index 8695f73..9df8c90 100644 --- a/app/Libraries/MyAuth/GoogleAuth.php +++ b/app/Libraries/MyAuth/GoogleAuth.php @@ -4,7 +4,7 @@ namespace App\Libraries\MyAuth; use App\Entities\UserEntity; use App\Libraries\MySocket\GoogleSocket; -use App\Models\SNSUserModel; +use App\Models\UserSNSModel; use App\Models\UserModel; use CodeIgniter\Exceptions\PageNotFoundException; use Google\Service\Oauth2; @@ -13,29 +13,27 @@ class GoogleAuth extends MyAuth { private ?GoogleSocket $_mySocket = null; private string $_site = "GOOGLE"; - private ?SNSUserModel $_model = null; - private string $token_code = ""; + private ?UserSNSModel $_model = null; private string $access_code = ""; - public function __construct(string $token_code, string $access_code) + public function __construct(string $access_code) { parent::__construct(); - $this->token_code = $token_code; $this->access_code = $access_code; } public function getMySocket(): GoogleSocket { if ($this->_mySocket === null) { - $this->_mySocket = new GoogleSocket($this->token_code); + $this->_mySocket = new GoogleSocket(); $this->_mySocket->setToken($this->access_code); } return $this->_mySocket; } - final protected function getModel(): SNSUserModel + final protected function getModel(): UserSNSModel { if ($this->_model === null) { - $this->_model = model(SNSUserModel::class); + $this->_model = model(UserSNSModel::class); } return $this->_model; } @@ -71,12 +69,18 @@ class GoogleAuth extends MyAuth public function checkUser(): UserEntity { try { - //Google 서비스 설정 + // 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)); + //기존 등록된 사용자가 있는지 검사 - $this->getModel()->where(SNSUserModel::SITE, $this->_site); + $this->getModel()->where(UserSNSModel::SITE, $this->_site); $entity = $this->getModel()->getEntityByID($authInfo['id']); if ($entity === null) { //없다면 새로 등록 @@ -103,6 +107,9 @@ class GoogleAuth extends MyAuth throw new PageNotFoundException("{$this->_site}의{$authInfo['email']}:{$authInfo['name']}님은 아직 사용자 연결이 이루어지지 않았습니다. "); } return $user_entity; + } catch (\Google_Service_Exception $e) { + log_message('error', '구글 서비스 예외: ' . $e->getMessage()); + throw new PageNotFoundException("구글 로그인 중 오류가 발생했습니다. 다시 시도해 주세요."); } catch (\Exception $e) { log_message('error', $e->getMessage()); throw new PageNotFoundException("관리자에게 문의하시기 바랍니다.
{$e->getMessage()}"); diff --git a/app/Libraries/MySocket/GoogleSocket.php b/app/Libraries/MySocket/GoogleSocket.php index 753b8c6..2d5cd1b 100644 --- a/app/Libraries/MySocket/GoogleSocket.php +++ b/app/Libraries/MySocket/GoogleSocket.php @@ -10,17 +10,23 @@ use Google\Service\Oauth2; class GoogleSocket extends Client { private $session; - private string $token_code; - public function __construct(string $token_code) + private string $_access_token = ""; + private string $_token_name = "access_token"; + public function __construct() { parent::__construct(); - $this->setAuthConfig(env('socket.google.api.config_file')); + $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(); - $this->token_code = $token_code; } public function setToken(string $access_code): void @@ -30,15 +36,53 @@ class GoogleSocket extends Client if (isset($tokenInfo['error'])) { throw new ConfigException($tokenInfo['error']); } - $token = $tokenInfo[$this->token_code]; + // dd($tokenInfo); + $this->_access_token = $tokenInfo[$this->_token_name]; // Google Service에 접근하기 위해 Access Token 설정 - $this->setAccessToken($token); + $this->setAccessToken([ + 'access_token' => $this->_access_token, + 'expires_in' => 3600, + 'created' => time(), + ]); // 세션에 Token 값 설정 - $this->session->set($this->token_code, $token); + $this->session->set($this->_token_name, $this->_access_token); } - public function getToken(): ?string + public function getToken(): string { - return $this->session->get($this->token_code); + 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/Models/SNSUserModel.php b/app/Models/UserSNSModel.php similarity index 58% rename from app/Models/SNSUserModel.php rename to app/Models/UserSNSModel.php index becee9d..d7d1b54 100644 --- a/app/Models/SNSUserModel.php +++ b/app/Models/UserSNSModel.php @@ -2,18 +2,18 @@ namespace App\Models; -use App\Entities\SNSUSerEntity; +use App\Entities\UserSNSEntity; use App\Models\CommonModel; -class SNSUserModel extends CommonModel +class UserSNSModel extends CommonModel { - const TABLE = "sns_users"; + const TABLE = "user_sns"; const PK = "uid"; const TITLE = "name"; const SITE = "site"; protected $table = self::TABLE; protected $primaryKey = self::PK; - protected $returnType = SNSUSerEntity::class; + protected $returnType = UserSNSEntity::class; protected $allowedFields = [ "site", "id", @@ -43,7 +43,10 @@ class SNSUserModel extends CommonModel $rule = "required|trim|string"; break; case "email": - $rule = "if_exist|trim|valid_email"; + $rule = "required|trim|valid_email"; + break; + case "detail": + $rule = "required|trim|string"; break; default: $rule = parent::getFieldRule($action, $field); @@ -51,25 +54,37 @@ class SNSUserModel extends CommonModel } return $rule; } - public function getEntityByPK(string $uid): null|SNSUSerEntity + protected function convertEntityData(string $field, array $formDatas): mixed + { + switch ($field) { + case "detail": //content등 textarea를 사용한 Field + $value = htmlentities($formDatas[$field], ENT_QUOTES); + break; + default: + $value = parent::convertEntityData($field, $formDatas); + break; + } + return $value; + } + public function getEntityByPK(string $uid): null|UserSNSEntity { $this->where($this->getPKField(), intval($uid)); return $this->getEntity(); } - public function getEntityByID(string $id): null|SNSUSerEntity + public function getEntityByID(string $id): null|UserSNSEntity { $this->where('id', $id); return $this->getEntity(); } //create용 - public function create(array $formDatas = []): SNSUSerEntity + public function create(array $formDatas = []): UserSNSEntity { - return $this->create_process(new SNSUSerEntity(), $formDatas); + return $this->create_process(new UserSNSEntity(), $formDatas); } //modify용 - public function modify(SNSUSerEntity $entity, array $formDatas): SNSUSerEntity + public function modify(UserSNSEntity $entity, array $formDatas): UserSNSEntity { return $this->modify_process($entity, $formDatas); }