787 lines
29 KiB
PHP
787 lines
29 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Web\Mypage;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Services\MemInfoService;
|
|
use App\Services\Danal\DanalAuthtelService;
|
|
use App\Services\Dozn\DoznAccountAuthService;
|
|
use App\Repositories\Member\MemberAuthRepository;
|
|
use App\Support\LegacyCrypto\CiSeedCrypto;
|
|
use App\Support\LegacyCrypto\CiPassword;
|
|
use Illuminate\Validation\Rule;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Arr;
|
|
|
|
|
|
final class InfoGateController extends Controller
|
|
{
|
|
public function __construct(
|
|
private readonly CiSeedCrypto $seed,
|
|
) {}
|
|
/**
|
|
* 비밀번호 재인증 화면
|
|
*/
|
|
public function show(Request $request)
|
|
{
|
|
$gate = (array) $request->session()->get('mypage_gate', []);
|
|
$ok = (bool) ($gate['ok'] ?? false);
|
|
$at = (int) ($gate['at'] ?? 0);
|
|
$ttlSeconds = 5 * 60;
|
|
$isValid = $ok && $at > 0 && (time() - $at) <= $ttlSeconds;
|
|
|
|
if ($isValid) {
|
|
return redirect()->to('/mypage/info_renew');
|
|
}
|
|
|
|
return view('web.mypage.info.gate');
|
|
}
|
|
|
|
|
|
public function info_renew(Request $request, MemInfoService $memInfoService)
|
|
{
|
|
// gate (기존 그대로)
|
|
$gate = (array) $request->session()->get('mypage_gate', []);
|
|
$gateOk = (bool) Arr::get($gate, 'ok', false);
|
|
$gateAt = (int) Arr::get($gate, 'at', 0);
|
|
|
|
$ttlSec = 5 * 60;
|
|
$nowTs = now()->timestamp;
|
|
$expireTs = ($gateOk && $gateAt > 0) ? ($gateAt + $ttlSec) : 0;
|
|
$remainSec = ($expireTs > 0) ? max(0, $expireTs - $nowTs) : 0;
|
|
$isGateValid = ($remainSec > 0);
|
|
|
|
// 회원정보: _sess 기반
|
|
$sess = (array) $request->session()->get('_sess', []);
|
|
|
|
$memberName = (string) Arr::get($sess, '_mname', '');
|
|
$memberEmail = (string) Arr::get($sess, '_mid', '');
|
|
$dtReg = (string) Arr::get($sess, '_dt_reg', '');
|
|
$memNo = (int) Arr::get($sess, '_mno', 0);
|
|
$rawPhone = (string) Arr::get($sess, '_mcell', '');
|
|
|
|
// 전화번호 복호 (인증 완료 상태라 마스킹 제외)
|
|
$memberPhone = (string) $this->seed->decrypt($rawPhone);
|
|
$user = $request->user();
|
|
$withdrawBankName = (string)($user->withdraw_bank_name ?? $user->bank_name ?? '');
|
|
$withdrawAccount = (string)($user->withdraw_account ?? $user->bank_account ?? '');
|
|
$hasWithdrawAccount = ($withdrawBankName !== '' && $withdrawAccount !== '');
|
|
|
|
$recv = $memNo > 0
|
|
? $memInfoService->getReceive($memNo)
|
|
: ['rcv_email' => 'n', 'rcv_sms' => 'n', 'out_account' => null];
|
|
|
|
$agreeEmail = $recv['rcv_email'];
|
|
$agreeSms = $recv['rcv_sms'];
|
|
$outAccount = $recv['out_account'] ?? null;
|
|
|
|
return view('web.mypage.info.renew', [
|
|
// gate
|
|
'ttlSec' => $ttlSec,
|
|
'expireTs' => (int) $expireTs,
|
|
'remainSec' => (int) $remainSec,
|
|
'isGateValid' => (bool) $isGateValid,
|
|
|
|
// member (sess)
|
|
'memberName' => $memberName,
|
|
'memberEmail' => $memberEmail,
|
|
'memberPhone' => $memberPhone,
|
|
'memberDtReg' => $dtReg,
|
|
|
|
// etc
|
|
'hasWithdrawAccount' => (bool) $hasWithdrawAccount,
|
|
'agreeEmail' => $agreeEmail,
|
|
'agreeSms' => $agreeSms,
|
|
'outAccount' => $outAccount,
|
|
]);
|
|
}
|
|
|
|
|
|
/**
|
|
* 재인증을 위한 연장 및 세셔초기화
|
|
*/
|
|
public function gateReset(Request $request)
|
|
{
|
|
$ttlSec = 5 * 60;
|
|
$now = time();
|
|
|
|
$gate = (array) $request->session()->get('mypage_gate', []);
|
|
$gateOk = (bool)($gate['ok'] ?? false);
|
|
$gateAt = (int) ($gate['at'] ?? 0);
|
|
|
|
$expireTs = ($gateOk && $gateAt > 0) ? ($gateAt + $ttlSec) : 0;
|
|
$isValid = ($expireTs > 0) && ($expireTs > $now);
|
|
|
|
if ($isValid) {
|
|
// 남은 시간이 있으면: 5분 연장(= at를 현재로 갱신)
|
|
$request->session()->put('mypage_gate', [
|
|
'ok' => true,
|
|
'email' => (string)($gate['email'] ?? ''),
|
|
'at' => $now,
|
|
]);
|
|
$request->session()->save();
|
|
|
|
}else{
|
|
// 시간이 끝났으면: 초기화
|
|
$request->session()->forget('mypage_gate');
|
|
$request->session()->save();
|
|
}
|
|
// 인덱스로 보내기
|
|
return redirect()->route('web.mypage.info.index');
|
|
}
|
|
|
|
/**
|
|
* 비밀번호 재인증 처리
|
|
*/
|
|
public function verify(Request $request, MemInfoService $memInfoService)
|
|
{
|
|
$request->validate([
|
|
'password' => ['required', 'string'],
|
|
], [
|
|
'password.required' => '비밀번호를 입력해 주세요.',
|
|
]);
|
|
|
|
$sess = (array) $request->session()->get('_sess', []);
|
|
$isLogin = (bool) ($sess['_login_'] ?? false);
|
|
$email = (string) ($sess['_mid'] ?? '');
|
|
|
|
if (!$isLogin || $email === '') {
|
|
return redirect()->route('web.auth.login', ['return_url' => url('/mypage/info')]);
|
|
}
|
|
|
|
$pw = (string) $request->input('password');
|
|
|
|
$res = $memInfoService->attemptLegacyLogin([
|
|
'email' => $email,
|
|
'password' => $pw,
|
|
'ip' => $request->ip(),
|
|
'ua' => substr((string) $request->userAgent(), 0, 500),
|
|
'return_url' => url('/mypage/info'),
|
|
]);
|
|
|
|
$ok = (bool)($res['ok'] ?? $res['success'] ?? false);
|
|
|
|
if (!$ok) {
|
|
$msg = (string)($res['message'] ?? '비밀번호가 일치하지 않습니다.');
|
|
return back()
|
|
->withErrors(['password' => $msg]) // 레이어 알림 스크립트가 이걸 잡음
|
|
->withInput($request->except('password'));
|
|
}
|
|
|
|
// 게이트 통과 세션 (예: 30분)
|
|
$request->session()->put('mypage_gate', [
|
|
'ok' => true,
|
|
'email' => $email,
|
|
'at' => time(),
|
|
]);
|
|
|
|
return redirect()->route('web.mypage.info.renew');
|
|
}
|
|
|
|
public function passReady(Request $request)
|
|
{
|
|
// 목적 저장 (result에서 분기용)
|
|
$purpose = (string) $request->input('purpose', 'mypage_phone_change');
|
|
$request->session()->put('mypage.pass_purpose', $purpose);
|
|
$request->session()->save();
|
|
|
|
$danal = app(\App\Services\Danal\DanalAuthtelService::class)->prepare([
|
|
'targetUrl' => route('web.mypage.info.danal.result'),
|
|
'backUrl' => route('web.mypage.info.renew'), // 취소/뒤로가기
|
|
'cpTitle' => request()->getHost(),
|
|
]);
|
|
|
|
if (!($danal['ok'] ?? false)) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => $danal['message'] ?? '본인인증 준비에 실패했습니다. 잠시 후 다시 시도해 주세요.',
|
|
], 500);
|
|
}
|
|
|
|
// 필요하면 txid 저장 (회원가입과 동일)
|
|
$request->session()->put('mypage.danal', [
|
|
'txid' => $danal['txid'] ?? null,
|
|
'created_at' => now()->toDateTimeString(),
|
|
'purpose' => $purpose,
|
|
]);
|
|
$request->session()->save();
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'reason' => 'danal_ready',
|
|
'popup' => [
|
|
'url' => route('web.mypage.info.danal.start'),
|
|
'fields' => $danal['fields'],
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function danalStart(Request $request)
|
|
{
|
|
$fieldsJson = (string) $request->input('fields', '');
|
|
$fields = json_decode($fieldsJson, true);
|
|
|
|
if (!is_array($fields) || empty($fields)) {
|
|
abort(400, 'Invalid Danal fields');
|
|
}
|
|
|
|
$platform = strtolower((string) $request->input('platform', ($fields['platform'] ?? '')));
|
|
$isMobile = false;
|
|
if ($platform === 'mobile') {
|
|
$isMobile = true;
|
|
} elseif ($platform === 'web') {
|
|
$isMobile = false;
|
|
} else {
|
|
$ua = (string) $request->header('User-Agent', '');
|
|
$isMobile = (bool) preg_match('/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i', $ua);
|
|
}
|
|
|
|
$action = $isMobile
|
|
? 'https://wauth.teledit.com/Danal/WebAuth/Mobile/Start.php'
|
|
: 'https://wauth.teledit.com/Danal/WebAuth/Web/Start.php';
|
|
|
|
unset($fields['platform']);
|
|
|
|
// 기존 autosubmit 뷰 재사용 OK
|
|
return view('web.auth.danal_autosubmit', [
|
|
'action' => $action,
|
|
'fields' => $fields,
|
|
'isMobile' => $isMobile,
|
|
]);
|
|
}
|
|
|
|
|
|
public function danalResult(
|
|
Request $request,
|
|
DanalAuthtelService $danal,
|
|
MemberAuthRepository $repo
|
|
) {
|
|
$payload = $request->all();
|
|
|
|
$tid = (string)($payload['TID'] ?? '');
|
|
if ($tid === '') {
|
|
return response()->view('web.auth.danal_finish_top', [
|
|
'ok' => false,
|
|
'message' => 'TID가 없습니다.',
|
|
'redirect' => route('web.mypage.info.index'),
|
|
]);
|
|
}
|
|
|
|
// CI와 동일: TID로 CONFIRM
|
|
$res = $danal->confirm($tid, 0, 1);
|
|
|
|
// 로그 저장 (성공/실패 무조건)
|
|
$logSeq = $repo->insertDanalAuthLog('M', (array) $res);
|
|
if ($logSeq > 0) {
|
|
$request->session()->put('mypage.pass.danal_log_seq', $logSeq);
|
|
}
|
|
|
|
$ok = (($res['RETURNCODE'] ?? '') === '0000');
|
|
if (!$ok) {
|
|
return response()->view('web.auth.danal_finish_top', [
|
|
'ok' => false,
|
|
'message' => ($res['RETURNMSG'] ?? '본인인증에 실패했습니다.') . ' (' . ($res['RETURNCODE'] ?? 'NO_CODE') . ')',
|
|
'redirect' => route('web.mypage.info.index'),
|
|
]);
|
|
}
|
|
|
|
// 목적이 마이페이지 연락처 변경일 때만 추가 검증
|
|
$purpose = (string) $request->session()->get('mypage.pass_purpose', '');
|
|
if ($purpose === 'mypage_phone_change') {
|
|
|
|
$sess = (array) $request->session()->get('_sess', []);
|
|
$memNo = (int) ($sess['_mno'] ?? 0);
|
|
|
|
if ($memNo <= 0) {
|
|
return response()->view('web.auth.danal_finish_top', [
|
|
'ok' => false,
|
|
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인 후 시도해 주세요.',
|
|
'redirect' => route('web.auth.login'),
|
|
]);
|
|
}
|
|
|
|
$svc = app(\App\Services\MypageInfoService::class);
|
|
|
|
//연락처 검증
|
|
$check = $svc->validatePassPhoneChange($sess, (array) $res);
|
|
if (!($check['ok'] ?? false)) {
|
|
return response()->view('web.auth.danal_finish_top', [
|
|
'ok' => false,
|
|
'message' => $check['message'] ?? '연락처 변경 검증에 실패했습니다.',
|
|
'redirect' => route('web.mypage.info.index'),
|
|
]);
|
|
}
|
|
|
|
//전화번호 저장
|
|
$check = $svc->commitPhoneChange($memNo, (array) $res);
|
|
if (!($check['ok'] ?? false)) {
|
|
return response()->view('web.auth.danal_finish_top', [
|
|
'ok' => false,
|
|
'message' => $check['message'] ?? '연락처 저장에 실패했습니다.',
|
|
'redirect' => route('web.mypage.info.index'),
|
|
]);
|
|
}
|
|
|
|
$request->session()->put('_sess._mcell', $check['_cell'] ?? ''); //전화번호 변경
|
|
|
|
}else{
|
|
return response()->view('web.auth.danal_finish_top', [
|
|
'ok' => false,
|
|
'message' => '요청이 올바르지 않습니다. 다시 시도해 주세요.',
|
|
'redirect' => route('web.mypage.info.index'),
|
|
]);
|
|
}
|
|
|
|
// 성공: 마이페이지 인증 플래그 세션 저장
|
|
$request->session()->forget('mypage.pass');
|
|
$request->session()->forget('mypage.danal');
|
|
|
|
$request->session()->save();
|
|
|
|
return response()->view('web.auth.danal_finish_top', [
|
|
'ok' => true,
|
|
'message' => '본인인증이 완료되었습니다.',
|
|
'redirect' => url('/mypage/info_renew'),
|
|
]);
|
|
}
|
|
|
|
/*비밀번호 변경 저장*/
|
|
public function passwordUpdate(Request $request, MemInfoService $memInfoService, MemberAuthRepository $repo)
|
|
{
|
|
if (!$this->isGateOk($request)) {
|
|
return $this->gateFailJson($request, '인증 시간이 만료되었습니다. 다시 인증해 주세요.');
|
|
}
|
|
|
|
// 로그인 세션
|
|
$sess = (array) $request->session()->get('_sess', []);
|
|
$isLogin = (bool) ($sess['_login_'] ?? false);
|
|
$email = (string) ($sess['_mid'] ?? '');
|
|
$memNo = (int) ($sess['_mno'] ?? 0);
|
|
|
|
if (!$isLogin || $email === '' || $memNo <= 0) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인해 주세요.',
|
|
'redirect' => route('web.auth.login'),
|
|
], 401);
|
|
}
|
|
|
|
// 검증 (요청하신 메시지 그대로)
|
|
$request->validate([
|
|
'current_password' => ['required', 'string'],
|
|
'password' => [
|
|
'required',
|
|
'string',
|
|
'min:8',
|
|
'max:20',
|
|
// 영문+숫자+특수문자 포함
|
|
'regex:/^(?=.*[A-Za-z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,20}$/',
|
|
'confirmed', // password_confirmation
|
|
],
|
|
], [
|
|
'password.required' => '비밀번호를 입력해 주세요.',
|
|
'password.min' => '비밀번호는 8자리 이상이어야 합니다.',
|
|
'password.max' => '비밀번호는 20자리를 초과할 수 없습니다.',
|
|
'password.regex' => '비밀번호는 영문+숫자+특수문자를 포함해야 합니다.',
|
|
]);
|
|
|
|
$currentPw = (string) $request->input('current_password');
|
|
$newPw = (string) $request->input('password');
|
|
|
|
// 현재 비밀번호 확인(기존 attemptLegacyLogin 로직 재사용)
|
|
$res = $memInfoService->attemptLegacyLogin([
|
|
'email' => $email,
|
|
'password' => $currentPw,
|
|
'ip' => $request->ip(),
|
|
'ua' => substr((string) $request->userAgent(), 0, 500),
|
|
'return_url' => url('/mypage/info_renew'),
|
|
]);
|
|
|
|
$ok = (bool)($res['ok'] ?? $res['success'] ?? false);
|
|
if (!$ok) {
|
|
// 레이어에서 보여줄 메시지
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => (string)($res['message'] ?? '현재 비밀번호가 일치하지 않습니다.'),
|
|
], 422);
|
|
}
|
|
|
|
// 변경 저장(레포 이미 존재) + 성공로그(레포 이미 존재)
|
|
$repo->updatePasswordOnly($memNo, $newPw);
|
|
$repo->logPasswordResetSuccess(
|
|
$memNo,
|
|
$email,
|
|
(string) $request->ip(),
|
|
(string) $request->userAgent(),
|
|
'S'
|
|
);
|
|
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'message' => '비밀번호가 변경되었습니다.',
|
|
]);
|
|
}
|
|
|
|
//2차 비밀번호 변경
|
|
public function updatePin2(
|
|
Request $request,
|
|
MemInfoService $memInfoService,
|
|
MemberAuthRepository $repo
|
|
) {
|
|
if (!$this->isGateOk($request)) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '인증 시간이 만료되었습니다. 다시 인증해 주세요.',
|
|
], 419);
|
|
}
|
|
|
|
// 입력 검증(메시지 그대로)
|
|
$request->validate([
|
|
'current_password' => ['required', 'string'],
|
|
'current_pin2' => ['required', 'digits:4'],
|
|
'pin2' => ['required', 'digits:4'],
|
|
'pin2_confirmation' => ['required', 'same:pin2'],
|
|
], [
|
|
'current_password.required' => '이전 비밀번호를 입력해 주세요.',
|
|
|
|
'current_pin2.required' => '이전 2차 비밀번호(숫자 4자리)를 입력해 주세요.',
|
|
'current_pin2.digits' => '이전 2차 비밀번호는 숫자 4자리여야 합니다.',
|
|
|
|
'pin2.required' => '2차 비밀번호(숫자 4자리)를 입력해 주세요.',
|
|
'pin2.digits' => '2차 비밀번호는 숫자 4자리여야 합니다.',
|
|
'pin2_confirmation.required' => '2차 비밀번호 확인을 입력해 주세요.',
|
|
'pin2_confirmation.same' => '2차 비밀번호 확인이 일치하지 않습니다.',
|
|
]);
|
|
|
|
// 세션에서 mem_no/email 확보
|
|
$sess = (array) $request->session()->get('_sess', []);
|
|
$isLogin = (bool) ($sess['_login_'] ?? false);
|
|
$email = (string) ($sess['_mid'] ?? '');
|
|
$memNo = (int) ($sess['_mno'] ?? 0);
|
|
|
|
if (!$isLogin || $email === '' || $memNo <= 0) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인 후 시도해 주세요.',
|
|
], 401);
|
|
}
|
|
|
|
// 1) 로그인 비밀번호(1차) 검증 (기존 attemptLegacyLogin 재사용)
|
|
$currentPw = (string) $request->input('current_password');
|
|
|
|
$res = $memInfoService->attemptLegacyLogin([
|
|
'email' => $email,
|
|
'password' => $currentPw,
|
|
'ip' => $request->ip(),
|
|
'ua' => substr((string) $request->userAgent(), 0, 500),
|
|
'return_url' => url('/mypage/info_renew'),
|
|
]);
|
|
|
|
$pwOk = (bool)($res['ok'] ?? $res['success'] ?? false);
|
|
if (!$pwOk) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'reason' => 'invalid_current_password',
|
|
'message' => (string)($res['message'] ?? '이전 비밀번호가 일치하지 않습니다.'),
|
|
], 422);
|
|
}
|
|
|
|
// 2) 현재 2차 비밀번호 검증
|
|
$currentPin2 = (string) $request->input('current_pin2');
|
|
$pin2Ok = $repo->verifyPin2($memNo, $currentPin2);
|
|
|
|
if (!$pin2Ok) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'reason' => 'invalid_current_pin2',
|
|
'message' => '이전 2차 비밀번호가 일치하지 않습니다.',
|
|
], 422);
|
|
}
|
|
|
|
// 3) 새 2차 비밀번호 저장
|
|
$newPin2 = (string) $request->input('pin2');
|
|
|
|
try {
|
|
$repo->updatePin2Only($memNo, $newPin2);
|
|
$repo->logPasswordResetSuccess2Only(
|
|
$memNo,
|
|
$email,
|
|
(string) $request->ip(),
|
|
(string) $request->userAgent()
|
|
);
|
|
} catch (\Throwable $e) {
|
|
Log::error('[mypage] pin2 update failed', [
|
|
'mem_no' => $memNo,
|
|
'err' => $e->getMessage(),
|
|
]);
|
|
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '2차 비밀번호 변경에 실패했습니다. 잠시 후 다시 시도해 주세요.',
|
|
], 500);
|
|
}
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'message' => '2차 비밀번호가 변경되었습니다.',
|
|
]);
|
|
}
|
|
|
|
|
|
public function verifyOut(Request $request, DoznAccountAuthService $dozn, MemberAuthRepository $repo)
|
|
{
|
|
// 게이트 만료 처리(프로젝트 정책대로)
|
|
if (!$this->isGateOk($request)) {
|
|
return $this->gateFailJson($request, '인증이 만료되었습니다. 다시 인증해 주세요.');
|
|
}
|
|
|
|
// 레거시 세션 기준으로 memNo / 실명 확정
|
|
$sess = (array) $request->session()->get('_sess', []);
|
|
$memNo = (int) ($sess['_mno'] ?? 0);
|
|
$memberName = trim((string) ($sess['_mname'] ?? ''));
|
|
|
|
if ($memNo <= 0 || $memberName === '') {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인 후 시도해 주세요.',
|
|
'redirect' => route('web.auth.login'),
|
|
], 401);
|
|
}
|
|
|
|
$request->validate([
|
|
'pin2' => ['required','digits:4'],
|
|
'bank_code' => ['required','string'],
|
|
'account' => ['required','regex:/^\d+$/'],
|
|
'depositor' => ['required','string','max:50'],
|
|
], [
|
|
'pin2.required' => '2차 비밀번호(숫자 4자리)를 입력해 주세요.',
|
|
'pin2.digits' => '2차 비밀번호는 숫자 4자리여야 합니다.',
|
|
'bank_code.required' => '은행을 선택해 주세요.',
|
|
'account.required' => '계좌번호를 입력해 주세요.',
|
|
'account.regex' => '계좌번호는 숫자만 입력해 주세요.',
|
|
'depositor.required' => '예금주(성명)를 입력해 주세요.',
|
|
]);
|
|
|
|
$pin2 = trim((string) $request->input('pin2', ''));
|
|
$bankCode = trim((string) $request->input('bank_code', ''));
|
|
$account = trim((string) $request->input('account', ''));
|
|
$depositor = trim((string) $request->input('depositor', ''));
|
|
|
|
if ($depositor !== $memberName) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '가입자 성명과 예금주가 일치하지 않습니다.',
|
|
'errors' => ['depositor' => ['가입자 성명과 예금주가 일치하지 않습니다.']],
|
|
], 422);
|
|
}
|
|
|
|
// 1) 2차비번 검증 먼저
|
|
$okPin2 = $repo->verifyPin2($memNo, $pin2);
|
|
if (!$okPin2) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '2차 비밀번호가 올바르지 않습니다.',
|
|
'errors' => ['pin2' => ['2차 비밀번호가 올바르지 않습니다.']],
|
|
], 422);
|
|
}
|
|
|
|
// 2) Dozn 인증 + 저장
|
|
$res = $dozn->verifyAndSaveOutAccount(
|
|
$memNo,
|
|
$memberName, // 세션 실명
|
|
$depositor, // 위에서 실명 일치 확인됨
|
|
$bankCode,
|
|
$account,
|
|
true
|
|
);
|
|
|
|
return response()->json($res, 200);
|
|
}
|
|
|
|
/**
|
|
* 마케팅 수신 동의 저장 (email/sms 각각 변경 시 해당 dt만 업데이트)
|
|
* - gate(5분) 유효해야 함
|
|
* - mem_info: rcv_email, rcv_sms, dt_rcv_email, dt_rcv_sms
|
|
*/
|
|
public function marketingUpdate(Request $request, MemInfoService $memInfoService)
|
|
{
|
|
if (!$this->isGateOk($request)) {
|
|
return $this->gateFailJson($request, '인증 시간이 만료되었습니다. 다시 인증해 주세요.');
|
|
}
|
|
|
|
// 레거시 세션 기준
|
|
$sess = (array) $request->session()->get('_sess', []);
|
|
$isLogin = (bool) ($sess['_login_'] ?? false);
|
|
$memNo = (int) ($sess['_mno'] ?? 0);
|
|
|
|
if (!$isLogin || $memNo <= 0) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인해 주세요.',
|
|
'redirect' => route('web.auth.login'),
|
|
], 401);
|
|
}
|
|
|
|
$request->validate([
|
|
'rcv_email' => ['required', Rule::in(['y','n'])],
|
|
'rcv_sms' => ['required', Rule::in(['y','n'])],
|
|
], [
|
|
'rcv_email.required' => '이메일 수신 동의 값을 선택해 주세요.',
|
|
'rcv_sms.required' => 'SMS 수신 동의 값을 선택해 주세요.',
|
|
'rcv_email.in' => '이메일 수신 동의 값이 올바르지 않습니다.',
|
|
'rcv_sms.in' => 'SMS 수신 동의 값이 올바르지 않습니다.',
|
|
]);
|
|
|
|
$rcvEmail = (string) $request->input('rcv_email', 'n');
|
|
$rcvSms = (string) $request->input('rcv_sms', 'n');
|
|
|
|
try {
|
|
$result = $memInfoService->setReceiveSelective($memNo, $rcvEmail, $rcvSms);
|
|
|
|
// 세션/표시용 값이 따로 있으면 여기서 같이 갱신해도 됨(선택)
|
|
// 예: $request->session()->put('_sess.rcv_email', $rcvEmail);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'message' => $result['message'] ?? '수신 동의 설정이 저장되었습니다.',
|
|
'changed' => $result['changed'] ?? [],
|
|
], 200);
|
|
|
|
} catch (\Throwable $e) {
|
|
Log::error('[mypage] marketing consent update failed', [
|
|
'mem_no' => $memNo,
|
|
'err' => $e->getMessage(),
|
|
]);
|
|
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '수신 동의 저장에 실패했습니다. 잠시 후 다시 시도해 주세요.',
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* gate 유효성 체크 (mypage_gate.at만 사용, TTL=5분)
|
|
*/
|
|
private function isGateOk(Request $request, int $ttlSec = 300): bool
|
|
{
|
|
$gate = (array) $request->session()->get('mypage_gate', []);
|
|
$ok = (bool)($gate['ok'] ?? false);
|
|
$at = (int)($gate['at'] ?? 0);
|
|
|
|
if (!$ok || $at <= 0) return false;
|
|
|
|
return (time() - $at) <= $ttlSec;
|
|
}
|
|
|
|
/**
|
|
* gate 만료 공통 JSON 응답
|
|
*/
|
|
private function gateFailJson(Request $request, string $message = '인증이 필요합니다.')
|
|
{
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => $message,
|
|
'redirect' => route('web.mypage.info.index'), // gate 페이지로 유도
|
|
], 401);
|
|
}
|
|
|
|
//회원탈퇴
|
|
public function withdraw(
|
|
Request $request,
|
|
MemInfoService $memInfoService,
|
|
MemberAuthRepository $repo
|
|
) {
|
|
// gate(5분) 유효해야 함 (지금 페이지가 info_renew니까 정책 그대로)
|
|
if (!$this->isGateOk($request)) {
|
|
return $this->gateFailJson($request, '인증 시간이 만료되었습니다. 다시 인증해 주세요.');
|
|
}
|
|
|
|
// 입력 검증
|
|
$request->validate([
|
|
'agree' => ['required', 'in:1'],
|
|
'password' => ['required', 'string'],
|
|
'pin2' => ['required', 'digits:4'],
|
|
], [
|
|
'agree.required' => '안내사항 동의가 필요합니다.',
|
|
'agree.in' => '안내사항 동의가 필요합니다.',
|
|
'password.required' => '비밀번호를 입력해 주세요.',
|
|
'pin2.required' => '2차 비밀번호(숫자 4자리)를 입력해 주세요.',
|
|
'pin2.digits' => '2차 비밀번호는 숫자 4자리여야 합니다.',
|
|
]);
|
|
|
|
$sess = (array) $request->session()->get('_sess', []);
|
|
$memNo = (int) Arr::get($sess, '_mno', 0);
|
|
|
|
if ($memNo <= 0) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '로그인 정보가 확인되지 않습니다. 다시 로그인해 주세요.',
|
|
'redirect' => route('web.auth.login'),
|
|
], 401);
|
|
}
|
|
|
|
$pw = (string) $request->input('password');
|
|
$pin2 = (string) $request->input('pin2');
|
|
|
|
// ✅ 1차 비밀번호 검증(Repo)
|
|
if (!$repo->verifyLegacyPassword($memNo, $pw)) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '비밀번호가 일치하지 않습니다.',
|
|
'errors' => ['password' => ['비밀번호가 일치하지 않습니다.']],
|
|
], 422);
|
|
}
|
|
|
|
// ✅ 2차 비밀번호 검증(Repo)
|
|
if (!$repo->verifyPin2($memNo, $pin2)) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '2차 비밀번호가 일치하지 않습니다.',
|
|
'errors' => ['pin2' => ['2차 비밀번호가 일치하지 않습니다.']],
|
|
], 422);
|
|
}
|
|
|
|
// ✅ 탈퇴 가능 조건 검증 + 처리(Service)
|
|
try {
|
|
$res = $memInfoService->withdrawMember($memNo);
|
|
|
|
if (!($res['ok'] ?? false)) {
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => $res['message'] ?? '회원탈퇴가 불가합니다.',
|
|
], 422);
|
|
}
|
|
|
|
// 세션 종료 (레거시 세션 포함)
|
|
$request->session()->flush();
|
|
$request->session()->invalidate();
|
|
$request->session()->regenerateToken();
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'message' => $res['message'] ?? '회원탈퇴가 완료되었습니다.',
|
|
'redirect' => route('web.auth.login'),
|
|
]);
|
|
|
|
} catch (\Throwable $e) {
|
|
Log::error('[mypage] withdraw failed', [
|
|
'mem_no' => $memNo,
|
|
'err' => $e->getMessage(),
|
|
]);
|
|
|
|
return response()->json([
|
|
'ok' => false,
|
|
'message' => '회원탈퇴 처리 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.',
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
|
|
}
|