RegisterController.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <?php
  2. namespace App\Http\Controllers\Auth;
  3. use Illuminate\Foundation\Auth\RegistersUsers;
  4. use Illuminate\Support\Carbon;
  5. use Illuminate\Support\Facades\Mail;
  6. use Illuminate\Support\Facades\URL;
  7. use Illuminate\Support\Facades\Validator;
  8. use Illuminate\Support\Facades\Cache;
  9. use Illuminate\Http\Request;
  10. use Illuminate\Http\JsonResponse;
  11. use App\Http\Controllers\Controller;
  12. use App\Http\Traits\TossTrait;
  13. use App\Http\Traits\CryptTrait;
  14. use App\Http\Traits\TelegramTrait;
  15. use App\Providers\RouteServiceProvider;
  16. use App\Models\User;
  17. use App\Models\DTO\ResponseData;
  18. use App\Mail\VerifyLink;
  19. use App\Rules\AllowNickname;
  20. use App\Rules\NumberLength;
  21. use App\Rules\SpecialCharLength;
  22. use App\Rules\UppercaseLength;
  23. use App\Rules\DeniedEmail;
  24. use Exception;
  25. class RegisterController extends Controller
  26. {
  27. /*
  28. |--------------------------------------------------------------------------
  29. | Register Controller
  30. |--------------------------------------------------------------------------
  31. |
  32. | This controller handles the registration of new users as well as their
  33. | validation and creation. By default this controller uses a trait to
  34. | provide this functionality without requiring any additional code.
  35. |
  36. */
  37. use RegistersUsers, TossTrait, CryptTrait, TelegramTrait;
  38. /**
  39. * Where to redirect users after registration.
  40. *
  41. * @var string
  42. */
  43. protected $redirectTo = RouteServiceProvider::HOME;
  44. // 토스 인증서 본인인증 결과값
  45. protected array $tossData = [];
  46. /**
  47. * Create a new controller instance.
  48. *
  49. * @return void
  50. */
  51. public function __construct()
  52. {
  53. $this->middleware('guest');
  54. }
  55. /**
  56. * Show the application registration form.
  57. *
  58. * @return \Illuminate\View\View
  59. */
  60. public function showRegistrationForm()
  61. {
  62. $policy_1 = nl2br(config('user_register_policy_1')); // 이용약관
  63. $policy_2 = nl2br(config('user_register_policy_1')); // 개인정보처리방침
  64. // 비밀번호 조건 확인
  65. $passwordMinLength = config('password_min_length');
  66. $passwordUppercaseLength = config('password_uppercase_length');
  67. $passwordNumbersLength = config('password_numbers_length');
  68. $passwordSpecialcharsLength = config('password_specialchars_length');
  69. $passwordGuideTip = "";
  70. if($passwordMinLength > 0) {
  71. $passwordGuideTip .= sprintf('최소 %d자 이상, ', $passwordMinLength);
  72. }
  73. if($passwordUppercaseLength > 0) {
  74. $passwordGuideTip .= sprintf('대문자 %d자 이상, ', $passwordUppercaseLength);
  75. }
  76. if($passwordNumbersLength > 0) {
  77. $passwordGuideTip .= sprintf('숫자 %d자 이상, ', $passwordNumbersLength);
  78. }
  79. if($passwordSpecialcharsLength > 0) {
  80. $passwordGuideTip .= sprintf('특수문자 %d자 이상, ', $passwordSpecialcharsLength);
  81. }
  82. $passwordGuideTip = rtrim($passwordGuideTip, ', ');
  83. return view('auth.register', [
  84. 'policy_1' => $policy_1,
  85. 'policy_2' => $policy_2,
  86. 'passwordGuideTip' => $passwordGuideTip
  87. ]);
  88. }
  89. /**
  90. * Get a validator for an incoming registration request.
  91. *
  92. * @param array $data
  93. * @return \Illuminate\Contracts\Validation\Validator
  94. */
  95. protected function validator(array $data)
  96. {
  97. return Validator::make($data, [
  98. 'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email', new DeniedEmail],
  99. 'password' => ['required', 'string', 'min:' . config('password_min_length', 4), 'confirmed', new NumberLength, new SpecialCharLength, new UppercaseLength],
  100. 'nickname' => ['required', 'string', 'min:2', 'max:20', new AllowNickname],
  101. 'agree_1' => 'required|numeric|in:1',
  102. 'agree_2' => 'required|numeric|in:2'
  103. ], [], [
  104. 'email' => '이메일',
  105. 'password' => '비밀번호',
  106. 'nickname' => '닉네임',
  107. 'agree_1' => '이용약관 동의',
  108. 'agree_2' => '개인정보처리방침 동의'
  109. ]);
  110. }
  111. /**
  112. * Create a new user instance after a valid registration.
  113. *
  114. * @param array $data
  115. * @return \App\Models\User
  116. */
  117. protected function create(array $data): mixed
  118. {
  119. return (new User)->register($data);
  120. }
  121. /**
  122. * Handle a registration request for the application.
  123. *
  124. * @param \Illuminate\Http\Request $request
  125. * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
  126. */
  127. public function register(Request $request)
  128. {
  129. // 회원가입 차단 확인
  130. if (config('use_register_block')) {
  131. return back()->withErrors('현재 회원 신청이 차단되어 회원가입을 할 수 없습니다. 관리자에게 문의하십시오.');
  132. }
  133. $postData = $request->all();
  134. // 회원가입 유효성 검증
  135. $this->validator($postData)->validate();
  136. $user = $this->create($postData);
  137. $this->guard()->login($user); // 로그인 처리
  138. $user->markEmailAsVerified(); // 이메일 인증 처리
  139. // 회원가입 이메일 알림
  140. $this->registered($request, $user);
  141. $message = sprintf('%s 님 회원가입을 환영합니다.', $user->name ?? $user->nickname);
  142. return $request->wantsJson() ? new JsonResponse([], 201) : redirect($this->redirectPath())->with('message', $message);
  143. }
  144. /**
  145. * 이메일 검증 주소 전송
  146. * @method POST
  147. * @see /auth/register/sendVerifyLink
  148. */
  149. public function sendVerifyLink(Request $request, ResponseData $response): ResponseData
  150. {
  151. try {
  152. $email = $request->post('email');
  153. if (!$email) {
  154. throw new Exception('이메일을 입력해주세요.');
  155. }
  156. if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
  157. throw new Exception('이메일 형식이 아닙니다.');
  158. }
  159. // 중복 여부
  160. if ((new User)->where('email', $email)->exists()) {
  161. throw new Exception('이미 사용 중인 이메일입니다.');
  162. }
  163. // 유효성 확인
  164. if (!(new DeniedEmail)->passes(null, $email)) {
  165. throw new Exception('입력하신 이메일은 사용하실 수 없습니다.');
  166. }
  167. $token = sha1($email);
  168. $verifyExpireTime = Carbon::now()->addMinutes(VERIFY_EXPIRES_AT);
  169. $verifyLink = URL::temporarySignedRoute(
  170. 'auth.register.verifyEmail', $verifyExpireTime, [
  171. 'token' => $token
  172. ]
  173. );
  174. // 인증 메일 전송
  175. Mail::to($email)->send(new VerifyLink($verifyLink, VERIFY_EXPIRES_AT, $email));
  176. // 인증 메일 캐시 저장
  177. Cache::put('verifyEmailToken_' . $token, $token, $verifyExpireTime);
  178. Cache::put('verifyEmailStatus_' . $token, 0);
  179. return $response;
  180. } catch (Exception $e) {
  181. return $response::fromException($e);
  182. }
  183. }
  184. /**
  185. * 이메일 검증 확인
  186. * @method GET
  187. * @see /auth/register/verifyEmail/{token}
  188. */
  189. public function verifyEmail(Request $request)
  190. {
  191. if (!$request->hasValidSignature()) {
  192. abort(404);
  193. }
  194. $token = (string)$request->route('token');
  195. if (!hash_equals((string)Cache::get('verifyEmailToken_' . $token), $token)) {
  196. abort(403);
  197. }
  198. Cache::put('verifyEmailStatus_' . $token, 1);
  199. return alertClose('이메일 인증이 완료되었습니다.');
  200. }
  201. /**
  202. * 이메일 인증 여부 확인
  203. * @method GET
  204. * @see /auth/register/checkVerifiedEmail
  205. */
  206. public function checkVerifiedEmail(Request $request): string
  207. {
  208. return json_encode([
  209. 'success' => intval(Cache::get('verifyEmailStatus_' . sha1($request->post('email'))))
  210. ]);
  211. }
  212. /**
  213. * 회원가입 후 처리
  214. */
  215. public function registered(Request $request, $user)
  216. {
  217. $this->sendMessageToRegister($user);
  218. }
  219. }