박주니 개발 정리

register 진행시 주의사항 본문

회고/laravel

register 진행시 주의사항

박주니 2022. 5. 4. 18:18
728x90
반응형

cava 프로젝트를 진행하면서 node+javascript 위주로 하다가 laravel로 만들다보니 validation보다 jquery를 많이 의존해서 유효성검사를 진행했습니다. 하지만 laravel로 작업할 때 코드가 클린하기 위해서는 validation 기반으로 진행을 해야했고 유지보수를 하거나 협업을 할 때에도 모든 것을 jquery로 진행하게 되면 코드가 복잡해지는 것을 보면서 핵심이 되는 부분만 새로 간단하게 만들어서 만들어봤습니다. 

 

1. 회원가입 버튼은 type submit으로 해서 validation을 거칠 수 있게 만듭니다. 

  • 이유) ajax을 사용해서 click event을 진행할시에 validation에 대한 메시지를 제대로 받지 못할 뿐더러 controller에서 response()->json()에 값을 담아서 그것을 또 프론트에서 append 보이게 해야 하기 때문에 최대한 form tag를 활용합니다. 

2. 조건 성립시 localStorage를 활용해서 회원가입 버튼 조건 부합시 진행할 수 있게 만듭니다.

  • 이유) 아이디 중복확인을 할 때에도 버튼을 안눌르고 클릭할 수도 있고 비밀번호 확인 성립되는 지 여부 확인도 안하고 누를 수도 있고 클라이언트가 요구하는 다양한 조건에 성립되지 않을 때 회원가입 버튼을 클릭시 다 controller을 거치게 하면 그건 프론트엔드 기능을 제대로 하지 않는 것이기 때문에 서버 과부하를 방지합니다. 

3. ajax 사용시 controller에서 return response()->json()을 활용해서 구분해서 진행할 수 있게 만듭니다.

  • 이유) 예전에 javascript로 작업을 하다보니 php 기반을 잘몰라서 ajax을 사용할 때 controller을 활용하는 방법이 잘안나와있었습니다. 보니깐 ajax을 사용하면 crud 작성하고 return response()->json()으로 내보내서 그것을 success:function(response){} 에서 response로 받아서 진행하시면 됩니다. ajax으로 진행할 때 controller에서 dd 활용할 수가 없어서 Log::info를 자주 사용했습니다. 

지금 올리는 코드는 위에 세가지를 기반으로 blade, controller을 만들어봤습니다. 이 부분에 대한 코드 이해는 laravel crud를 이해하시고 오신다면 왜 이렇게 작성했는 지 확인할 수 있습니다. 포인트는 validation 활용편과 laravel crud 블로그에 올린거 봐주세요. 

 

  • register.blade.php
@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{ __('Register') }}</div>

                    <div class="card-body">
                        <form method="POST" action="{{ route('register') }}" onsubmit="return checkRegister()">
                            @csrf

                            <div class="row mb-3">
                                <label for="name" class="col-md-4 col-form-label text-md-end">{{ __('Name') }}</label>

                                <div class="col-md-6">
                                    <input id="name" type="text" class="form-control @error('name') is-invalid @enderror"
                                        name="name" value="{{ old('name') }}" required autofocus>

                                    @error('name')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror

                                    <input type="button" id="checkId" value="중복확인">
                                </div>
                            </div>

                            <div class="row mb-3">
                                <label for="email"
                                    class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>

                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control @error('email') is-invalid @enderror"
                                        name="email" value="{{ old('email') }}" required>

                                    @error('email')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="row mb-3">
                                <label for="password"
                                    class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password" type="password" id="password"
                                        class="form-control @error('password') is-invalid @enderror" name="password"
                                        required>

                                    @error('password')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="row mb-3">
                                <label for="password-confirm"
                                    class="col-md-4 col-form-label text-md-end">{{ __('Confirm Password') }}</label>

                                <div class="col-md-6">
                                    <input id="password-confirm" type="password" id="password-confirm"
                                        class="form-control" name="password_confirmation" required>
                                </div>
                            </div>

                            <button type="button" id="authBtn">인증</button>

                            <div class="row mb-0">
                                <div class="col-md-6 offset-md-4">
                                    <button type="submit" class="btn btn-primary">
                                        {{ __('Register') }}
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection
@section('javascript')
    <script>
        $(document).ready(function() {
            $.ajaxSetup({
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                }
            });
            localStorage.removeItem('name');
            localStorage.removeItem('confirmPwd');
            localStorage.removeItem('auth')
        })
        $("#checkId").on("click", function() {
            let name = $("#name").val();
            $.ajax({
                type: "GET",
                url: `/checkId/${name}`,
                success: function(response) {
                    if (response.message == 'success') {
                        localStorage.setItem('name', 1)
                        alert("사용 가능한 아이디입니다.")
                        
                    } else {
                        localStorage.setItem('name', 2)
                        alert("중복된 아이디가 있습니다.")
                        
                    }
                },
                error: function(request, status, error) {
                    console.log("code:" + request.status + "\n" + "message:" + request.responseText +
                        "\n" + "error:" + error);
                }
            })
        })

        // password, cofinrmpassword 비교
        $("#password, #password-confirm").on("change", function() {
            var password = $("#password").val();
            var confirmPassword = $("#password-confirm").val();

            var num = password.search(/[0-9]/g);
            var eng = password.search(/[a-z]/ig);
            var spe = password.search(/[`~!@@#$%^&*|₩₩₩'₩";:₩/?]/gi);
        // console.log(password.length)
        // console.log(num, eng, spe)
        // password 8자리이상 20자리 이하일경우에만 비교 
        if (password.length > 7 || password.length < 20) {
            if (password.search(/\s/) != -1) {
                alert("비밀번호는 공백 없이 입력해주세요.");
                return false;
            } 
            else {
                if (num >= 0 && eng >= 0 && spe >= 0) {
                    if (password == confirmPassword) {
                        localStorage.setItem('confirmPwd', 1)
                        alert("비밀번호가 일치합니다.")
                        
                    } else {
                        localStorage.setItem('confirmPwd', 2)
                        alert("비밀번호가 일치하지 않습니다.")
                        }
                    } else {
                        alert("영문,숫자, 특수문자를 혼합하여 입력해주세요.");
                    }
            }
        } 
        })

        $("#authBtn").on("click", function(){
            let name = localStorage.getItem('name')
            let password = localStorage.getItem('confirmPwd')
            console.log(name, password);

            if(name == 1 && password == 1){
                alert("인증이 완료되었습니다.")
                localStorage.setItem('auth', 1)
            }
            else{
                alert("인증 실패했습니다.")
                localStorage.setItem('auth', 2)
            }
        })

        function checkRegister(){
            let auth = localStorage.getItem('auth')
            if(auth == 1){
                alert('회원가입 진행중입니다.')
            }
            else{
                alert("회원가입 실패하셨습니다.")
                return false
            }
        }
    </script>
@endsection

 

  • 참고) script에서 정규식표현은 해당 코드는 제한을 하기 위함입니다. 좀 더 자세한 코드를 작성할 수 있었으나 우선 이건 프로젝트를 하다가 그저 회고하기 위해 만든 form임으로 나중에 만드실 때에는 input마다 제한을 주시길 바랍니다. 
  • CheckIdController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Log;

class CheckIdController extends Controller
{
    public function index($user){
        $userFirst = User::where('name', $user)->first();
        if(true == empty($userFirst)){
            return response()->json(['message'=>'success']);
        }
        else{
            return response()->json(['message' => 'fail']);
        }
        
    }
}
  • 참고) 아이디 중복확인 버튼 클릭시 이동해서 구분하는 controller입니다. 경로는 따로 설명하지 않겠습니다. 클릭시 이동해서 ajax으로 이용하시면 됩니다. 
  • RegisterController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\Models\User
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
            'role' => 'user',
            'status' => '2'
        ]);
    }
}
  • 참고) 이 controller은 laraval에서 제공하는 기본 controller입니다. column 추가 되거나 하시면 변경만 해서 활용하시면 됩니다. 새로 만들어서 작업하면 기본 제공하는 기능을 활용하지 못할 수 있으니 최대한 있는 register controller을 활용해주시면 됩니다.

그리고 이건 jquery 및 각 blade script을 사용하기 위해서는 @extends()에 연결된 blade를 확인해서 header에 jquery script 추가하고 @yield('content') 하단에 @yield('javascript')를 추가하시면 됩니다.

 

  • app.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>

    <!-- Fonts -->
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"
    integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
    </script>
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
            <div class="container">
                <a class="navbar-brand" href="{{ url('/') }}">
                    {{ config('app.name', 'Laravel') }}
                </a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
                    <span class="navbar-toggler-icon"></span>
                </button>

                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <!-- Left Side Of Navbar -->
                    <ul class="navbar-nav me-auto">

                    </ul>

                    <!-- Right Side Of Navbar -->
                    <ul class="navbar-nav ms-auto">
                        <!-- Authentication Links -->
                        @guest
                            @if (Route::has('login'))
                                <li class="nav-item">
                                    <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
                                </li>
                            @endif

                            @if (Route::has('register'))
                                <li class="nav-item">
                                    <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
                                </li>
                            @endif
                        @else
                            <li class="nav-item dropdown">
                                <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                    {{ Auth::user()->name }}
                                </a>

                                <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
                                    <a class="dropdown-item" href="{{ route('logout') }}"
                                       onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                        {{ __('Logout') }}
                                    </a>

                                    <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
                                        @csrf
                                    </form>
                                </div>
                            </li>
                        @endguest
                    </ul>
                </div>
            </div>
        </nav>

        <main class="py-4">
            @yield('content')
            @yield('javascript')
        </main>
    </div>
</body>
</html>
  • 참고) 이건 어디까지나 기본적으로 제공하는 @extends() 안에 있는 blade에서 해결한 것이고 나중에 협업에 일을 하시면 다른 blade로 작업할 수 있으니 꼭 그때는 extends 어디에 연결되어있는 지 확인하시고 진행하시길 바랍니다.
  • jquery script 경로
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"
    integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
    </script>
  • 참고) 다른 경로들을 사용을 해봤지만 저는 이 경로를 연결하고 사용할 때가 가장 편하게 잘돼서 추천을 합니다. 다만 더 간단한 방법이 있다면 알려주시면 감사하겠습니다. 

laravel로 프로젝트를 진행하면서 특히 회원가입을 진행할 때 validation 유효성 검사를 중점으로 두고 해야한다는 것을 다시 한번 느끼게 되었다. 로마의 가면 로마의 법을 따르는 것처럼 node javascript 기반으로 했을 때 문제가 없어서 프론트에서 제한만 잘하면 되겠지라는 안일한 생각이 이렇게 유지보수할 때나 협업할 때 불편함을 줄 수 있다는 것을 알게 되었고 이제는 그런 실수를 저지르지 말아야겠다.

728x90
반응형
Comments