팀 프로젝트 니마음-3

Cloudman·2022년 11월 18일
0

항해99

목록 보기
5/10

📒 1. 회원가입 페이지



📌 회원가입 관련 정리

  • 다양한 alert 메시지 출력 부분
    지난번과 다르게 이번에는 하나의 if 문에서 순차적으로 예외처리를 진행하게 만들었다.
    1) 아이디를 입력하지 않을시 메시지 출력
    2) 아이디가 정규식에 맞지 않을시 메시지 출력
    3) DB에 입력한 아이디가 있을 경우 메시지 출력
    4) 닉네임칸에 입력하지 않을시 메시지 출력
    5) 닉네임이 정규식에 맞지 않을시 메시지 출력
    6) DB에 입력한 닉네임이 있을 경우 메시지 출력
    7) 1차 비밀번호칸에 입력하지 않을시 메시지 출력
    8) 1차 비밀번호가 정규식에 맞지 않을시 메시지 출력
    9) 2차 비밀번호에 아무런 입력이 없을시 메시지 출력
    10) 1차와 2차 비밀번호가 일치하지 않을시 메시지 출력

위에 적힌 것으로 즉, 총 10종류의 경우에 대해 각각의 메시지를 출력한다.

하지만 if 문으로 위에서부터 내려오면서 작동하기에 맨 먼저 걸린것에 대한 알림 하나만을 띄우게 된다.



🔗 회원가입 API

암호화는 re 객체를 이용해서 sha256 방식으로 단방향 암호화를 거친다.
암호화 기술 중에서 한 쪽 방향 으로만 암호화 한다는 의미 이다.
암호화된 코드를 통해서는 다시 반대로 풀 수 없는 방식이다. 양방향 암호화는 반대로 하면 풀 수 있다.
DB 에 저장 할 때는 사용자들이 입력한 암호는 개발자 포함 아무도 몰라야 하니까 저장 하기전에 암호화가 필수다.
정규식 참고 링크 : https://wikidocs.net/4308

1. 기능 : 회원가입 처리 API
2. 작성자 : 6조 서혁수
3. 작성일자 : 2022-11-14
4. 수정사항 :
@app.route('/api/register', methods=['POST'])
def api_register():
    # 1. 양식에 사용될 정규식을 선언
    idreg = re.compile("^[0-9a-zA-Z]{5,20}$")                                               # ID 관련 정규식 영어 대/소문자, 숫자 0~9 까지 5~20 자로 제한
    pwreg = re.compile("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,16}$")  # PW 관련 정규식 영어 대/소문자, 숫자 0~9, 특수문자 반드시 사용 8~16자로 제한
    nickreg = re.compile("^[0-9a-zA-Z가-힣]{2,10}$")                                         # 닉네임 관련 정규식 영어 대/소문자, 한글 자음, 모음만 사용 불가능, 숫자 0~9 까지

    # 2. 클라이언트 로 부터 정보를 받기
    id_receive = request.form['id_give']                # 클라이언트 로 부터 ID 입력값 받아오기
    pw_receive = request.form['pw_give']                # 클라이언트 로 부터 PW 입력값 받아오기
    nickname_receive = request.form['nickname_give']    # 클라이언트 로 부터 닉네임 입력값 받아오기
    pwch_receive = request.form['pwch_give']            # 클라이언트 로 부터 2차 비밀번호 입력값 받아오기

    # 3. 받아온 정보를 바탕으로 정규식 검사
    check_id = idreg.match(id_receive)                  # 받아온 입력값을 정규식으로 검사
    check_pw = pwreg.match(pw_receive)
    check_nick = nickreg.match(nickname_receive)

    # 4. 로그인 시 예외 사항 관련 처리
    if id_receive == '':                                                                      # 아이디를 입력하지 않을시 메시지 출력
        return jsonify({'result': 'fail', 'msg': '아이디를 입력해 주세요 !'})
    elif check_id is None:                                                                    # 아이디가 정규식에 맞지 않을시 메시지 출력
        return jsonify({'result': 'fail', 'msg': '아이디 작성시 양식에 맞게 다시 입력해 주세요 !'})
    elif db.user.find_one({'id': id_receive}) is not None:                                    # DB에 입력한 아이디가 있을 경우 메시지 출력
        return jsonify({'result': 'fail', 'msg': '이미 사용중인 아이디가 있습니다 !'})
    elif nickname_receive == '':                                                              # 닉네임칸에 입력하지 않을시 메시지 출력
        return jsonify({'result': 'fail', 'msg': '닉네임을 입력해 주세요 !'})
    elif check_nick is None:                                                                  # 닉네임이 정규식에 맞지 않을시 메시지 출력
        return jsonify({'result': 'fail', 'msg': '닉네임 작성시 양식에 맞게 다시 입력해 주세요 !'})
    elif db.user.find_one({'nick': nickname_receive}) is not None:                            # DB에 입력한 닉네임이 있을 경우 메시지 출력
        return jsonify({'result': 'fail', 'msg': '이미 사용중인 닉네임이 있습니다 !'})
    elif pw_receive == '':                                                                    # 1차 비밀번호칸에 입력하지 않을시 메시지 출력
        return jsonify({'result': 'fail', 'msg': '비밀번호를 입력해 주세요 !'})
    elif check_pw is None:                                                                    # 1차 비밀번호가 정규식에 맞지 않을시 메시지 출력
        return jsonify({'result': 'fail', 'msg': '비밀번호를 양식에 맞게 입력해 주세요 !'})
    elif pwch_receive == '':                                                                  # 2차 비밀번호에 아무런 입력이 없을시 메시지 출력
        return jsonify({'result': 'fail', 'msg': '비밀번호를 한번 더 입력해 주세요 !'})
    elif pw_receive != pwch_receive:                                                          # 1차와 2차 비밀번호가 일치하지 않을시 메시지 출력
        return jsonify({'result': 'fail', 'msg': '비밀번호가 일치하지 않습니다 !'})

    # 5. 회원가입 완료 처리 부분
    if check_id and check_pw and check_nick:                                        # 예외사항을 모두 통과시에 작동
        pw_hash = hashlib.sha256(pw_receive.encode('utf-8')).hexdigest()            # 입력한 비밀번호를 암호화
        db.user.insert_one(                                                         # 입력한 값들을 모두 디비에 넣어준다.
            {'id': id_receive, 'pw': pw_hash, 'nick': nickname_receive})
        return jsonify({'result': 'success'})                                       # 결과를 result 키에 success 값을 반환
    else:
        return jsonify({'result': 'fail', 'msg': '양식에 맞게 입력해 주세요.'})        # 위의 모든 과정과 맞지 않으면 발생




📋 위의 코드에 대한 추가적인 설명 !!


📌 methods 의 전달 방식에 대한 설명

참고 링크 : https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=ktw3722&logNo=220676040801

  • GET : 서버의 데이터를 변경할 목적이 아닌 조회으 목적으로 사용
    전송할 데이터를 문자열 형태로 URL 의 뒤에 인수로 붙여서 전송 그래서 보안성이 없다.
  • 주소와 데이터의 구분
    ? : 전송되는 데이터(변수)의 시작
    & : 변수가 2개 이상일 경우 구분
  • POST : 서버의 데이터를 변경할 목적으로 사용 일반적으로 Form 은 post 방식으로 사용
    파일의 형태로 전송됨으로 URL 상에 나타나지 않아 보안성이 있다. GET 방식 보다 대용량으로 데이터 전송 가능

🔖 양식에 사용될 정규식을 선언

re 모듈의 컴파일 함수를 사용해서 변수에 정규식을 선언해서 담아준다.

idreg = re.compile("^[0-9a-zA-Z가-힣]{5,20}$")
pwreg = re.compile("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,16}$")
nickreg = re.compile("^[0-9a-zA-Z가-힣]{2,10}$")

🔖 클라이언트 로 부터 정보를 받기

POST 방식으로 서버로부터 데이터를 수신한다.
web 에서 ajax 로 담아서 post 로 요청 하면 request 라는 객체 안의 form 이라는 함수를 통해서 키값이 id_give 인 녀석을
id_receive 에 담는다는 의미이다. 아래의 pw, nick 도 다 이런식으로 해석하자.

id_receive = request.form['id_give']
pw_receive = request.form['pw_give']
nickname_receive = request.form['nickname_give']
pwch_receive = request.form['pwch_give']

🔖 받아온 정보를 바탕으로 정규식 검사

이제 가져온 값들을 정규식 함수를 이용해서 match 메서드로 내가 필요한 변수에 담긴 값들을 가지고 검사한다.
이 때, 결과가 맞지 않으면 none 을 반환하며 내가 원하는 변수에 담긴다.

check_id = idreg.match(id_receive)
check_pw = pwreg.match(pw_receive)
check_nick = nickreg.match(nickname_receive)

🔖 로그인 시 예외 사항 관련 처리 - 1

회원가입 시 중복값 및 여러가지 예외사항들을 처리를 한다.
jsonify 는 사용자가 json data 를 내보내도록 제공하는 flask 의 함수이다.
id_receive 에 아무 값이 없을 때 즉, 로그인 페이지에서 ID 입력칸에 아무런 값이 없으면 result 에 fail 을,
msg 에는 "아이디를 입력해 주세요 !" 가 담겨서 json 데이터를 리턴시킨다.
이 아래로는 모두 같은 패턴으로 이용

if id_receive == '':
    return jsonify({'result': 'fail', 'msg': '아이디를 입력해 주세요 !'})
elif check_id is None:
    return jsonify({'result': 'fail', 'msg': '아이디 작성시 양식에 맞게 다시 입력해 주세요 !'})

🔖 로그인 시 예외 사항 관련 처리 - 2

DB 에서 ID 값을 찾은경우 부터 쭉 돌아간다

DB 에서 'id' 키워드에 내가 로그인 페이지에서 입력한 값이 None 이 아니다. 즉 동일한 아이디가 존재할 경우
해당 아이디가 있는 딕셔너리를 find 에 담아준다.
이후에 해당 딕셔너리에 있는 키가 id 인 녀석에 있는 값을 idinput 에 담아준다.
그러고 나서 만약 id_receive 즉, 내가 입력한 아이디와 일치하면 '이미 사용중인 아이디가 있습니다 !' 로 리턴
이 아래로는 모두 같은 패턴으로 이용

elif db.user.find_one({'id': id_receive}) is not None:
    find = db.user.find_one({'id': id_receive})
    idinput = find['id']
    if id_receive == idinput:
        return jsonify({'result': 'fail', 'msg': '이미 사용중인 아이디가 있습니다 !'})

🔖 로그인 시 예외 사항 관련 처리 - 3

위의 예외사항 들 중에서 아무것도 걸리지 않고 양식도 맞게 입력 되었으면 회원가입을 완료한다.

하지만 pw_hash 라는 변수에다가 회원가입시 입력한 비밀번호를 hashlib 객체를 이용해서 sha256 방식으로 암호화 해서 넣는다.
이후에 DB의 user 라는 컬렉션에 받아온 정보들을 넣고 json 형태로 다시 success 로 반환

if check_id and check_pw and check_nick:
    pw_hash = hashlib.sha256(pw_receive.encode('utf-8')).hexdigest()
    db.user.insert_one(
        {'id': id_receive, 'pw': pw_hash, 'nick': nickname_receive})  ### 추가 1. insert 내용 변경
    return jsonify({'result': 'success'})
else:
    return jsonify({'result': 'fail', 'msg': '양식에 맞게 입력해 주세요.'})




🔗 회원가입 JS-1

// 1. 기능 : 회원가입
// 2. 작성자 : 6조 서혁수
// 3. 작성일자 : 2022-11-14
// 4. 수정사항 :
function register() {
	// ajax 의 기본형태는 딕셔너리 key - value
    // ajax 를 통해서(클라) 서버로 요청한다.
    $.ajax({
        type: "POST",
        url: "/api/register",
        data: {
            id_give: $('#userid').val(),
            pw_give: $('#userpw').val(),
            nickname_give: $('#usernick').val(),
            pwch_give: $('#userpwch').val()
        },
        success: function (response) {
            if (response['result'] == 'success') {
                alert('회원가입이 완료되었습니다.')          // 회원가입 메시지 출력
                window.location.href = '/login'         // 회원가입 완료시 로그인 창으로 돌아간다.
            } else {
                alert(response['msg'])                  // 회원가입 실패시 메시지 출력
            }
        }
    })
}

🔗 회원가입 JS-2

// 1. 기능 : 회원가입 경고문구 출력
// 2. 작성자 : 6조 서혁수
// 3. 작성일자 : 2022-11-14
// 4. 수정사항 :
// 1. 회원가입에 이용될 정규식 선언
// ID 관련 정규식 영어 대/소문자, 숫자 0~9 까지 5~20 자로 제한
// 닉네임 관련 정규식 영어 대/소문자, 한글 자음, 모음만 사용 불가능, 숫자 0~9 까지
// PW 관련 정규식 영어 대/소문자, 숫자 0~9, 특수문자 반드시 사용 8~16자로 제한
var id_reg = new RegExp('^[0-9a-zA-Z]{5,20}$')
var nick_reg = new RegExp('^[0-9a-zA-Z가-힣]{2,10}$')
var pw_reg = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,16}$/

let test1 = document.getElementById('userid')
let test3 = document.getElementById('usernick')
let test2 = document.getElementById('userpw')
let test4 = document.getElementById('userpwch')

// 2. 실시간 중복 아이디 확인 함수
function closeid() {
    // 입력값을 받아올 변수 선언
    let newValue
    $("#userid").on("propertychange change keyup paste input", function () {
        // 인풋값에 받아온 입력값을 newValue 에 담는다.
        newValue = $(this).val();
        if (newValue.match(id_reg) == null) {
            // 입력 값이 정규식에 맞지 않으면 경고문구 출력
            $('#result1').css('display', 'block')
            test1.classList.add('no')
        } else {
            // 입력 값이 정규식에 맞으면 경고문구 숨기기
            $('#result1').css('display', 'none')
            test1.classList.remove('no')
        }

        if (test1.hasClass('no') ||
            test2 ||
            test3 ||
            test4) {
        }
    });
}

// 3. 실시간 중복 닉네임 확인 함수
function closenick() {
    let newValue
    $("#usernick").on("propertychange change keyup paste input", function () {
        newValue = $(this).val();
        if (newValue.match(nick_reg) == null) {
            $('#result2').css('display', 'block')
        } else {
            $('#result2').css('display', 'none')
        }
    });
}

// 4. 실시간 1차 비밀번호 정규식 확인 함수
function closepw() {
    let newValue
    $("#userpw").on("propertychange change keyup paste input", function () {
        newValue = $(this).val();
        if (newValue.match(pw_reg) == null) {
            $('#result3').css('display', 'block')
        } else {
            $('#result3').css('display', 'none')
        }
    });
}

// 5. 실시간 1차 비밀번호 확인 함수
function closepwch() {
    // 1차 비밀번호 값 가져오기
    let newValue1 = $('#userpw').val()
    // 2차 비밀번호를 담을 새로운 변수 선언
    let newValue2
    $("#userpwch").on("propertychange change keyup paste input", function () {
        // 2차 비밀번호를
        newValue2 = $(this).val();
        // 인풋값에 받아온 입력값을 newValue2 에 담는다.
        if (newValue1 === newValue2) {
            // 1차 비밀번호와 2차 비밀번호가 일치하면 경고문구 감추기
            $('#result4').css('display', 'none')
        } else {
            // 1차 비밀번호와 2차 비밀번호가 일치하면 경고문구 출력
            $('#result4').css('display', 'block')
        }
    });
}




❓ 자바 스크립트 문제 발생

1. [ 실시간 input 값에 따라 경고문구 출력 관련 ]

innerHTML 는 안먹히고 text 로 하니까 먹히는걸 확인
div 는 텍스트 태그가 아니라서 불가능 했던걸로 추정
$('#result').innerHTML("확인")

결국 태그를 기본적으로는 display: none; 으로 하고 상황에 따라 css 속성을 변경하는 방법으로 변경

2. 아래의 정규식에서 new 가 왜 안돼는지 관련

정규식 참고 링크 : https://hamait.tistory.com/342,
https://java119.tistory.com/71 이 블로그의 비밀번호 정규식을 적용했다.

정규식(Regular Expression) 줄여서 regexp 라고 한다.
아래에 선언한 것 처럼 두가지 방식의 선언방식이 있다.
그리거 match 메서드를 이용하면 "문자열"에서 "정규표현식"에 매칭되는 항목들을 배열로 반환한다.

https://beomy.tistory.com/21 아래 두가지 방법에 대한 차이의 설명
정규식 패턴이 변경되는 경우 생성자 함수를 사용하여 동적으로 정규식을 만들 수 있다.
정규식 패턴이 계속 지속될 경우 아래의 방법중 new 연산자를 쓰지않는 방법을 사용

new 연산자는 객체를 생성하기 때문에 pw_reg 라는 변수는 new RegExp 라는 공간에 새로운 객체를 만들었기 때문에
new 연산자를 사용할 경우 제대로 적용이 안되는 경우가 생기기도 한다.
다만 확실지는 않고 이런 경우가 있었다는 정도

[ 회원가입 관련 정규식 변수 ]
순서대로 아이디, 닉네임, 비밀번호 정규식이다.
5~20자의 영문 대 소문자, 숫자만 사용 가능
2~10자 영문 대 소문자, 숫자, 한글만 사용 가능
8~16자 제한으로 영문 대 소문자, 숫자, 특수문자 모두 반드시 하나씩은 사용 해야 한다.

var id_reg = new RegExp('^[0-9a-zA-Z]{5,20}$')
var nick_reg = new RegExp('^[0-9a-zA-Z가-힣]{2,10}$')
var pw_reg = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,16}$/



📌 회원가입 관련 실시간 경고문구 함수

인풋 태그 안의 값들을 실시간으로 입력받아서 그 값을 기준으로 경고문구 텍스트가 담긴 태그를
실시간으로 화면상에 표현하고 감추는 기능을 하는 부분이다.

function closeid() {
    let newValue
    $("#userid").on("propertychange change keyup paste input", function () {
        newValue = $(this).val();
        if (newValue.match(id_reg) == null) {
            // 정규식 표현에 맞는 문자열이 없다면 null 을 반환 하기 때문에 그걸 이용해서 판단한다.
            // 위에서 선언한 newValue 부분의 값을 가져와서 정규식에 match 메서드를 이용해서 비교한다.
            // 해당 값이 맞지않음 즉, null 일 경우 경고문구 태그의 속성 display 를 block 으로 해서
            // 태그를 화면상에 나타내준다.
            $('#result1').css('display', 'block')
        } else {
            // 만약 값이 null 이 아니면 즉, 맞을 경우에는 다시 속성 dispaly 를 none 으로 해서 감춘다.
            $('#result1').css('display', 'none')
        }
    });
}



📌 실시간 1차 비밀번호 확인 함수

처음 입력한 비밀번호와 확인용 비밀번호가 일치하는지 확인해서 경고문구를 나타내고 감추는 부분

function closepwch() {
    // 첫번째 비밀번호 입력 부분의 값을 가져오는 변수를 선언해준다
    let newValue1 = $('#userpw').val()
    let newValue2
    $("#userpwch").on("propertychange change keyup paste input", function () {
        // 첫번째 변수와 두번째 변수의 값을 비교해서 그에 따라 경고문구의 display 속성을 나타내고 감춘다.
        newValue2 = $(this).val();
        if (newValue1 === newValue2) {
            $('#result4').css('display', 'none')
        } else {
            $('#result4').css('display', 'block')
        }
    });
}



회원가입 부분에서 꽤나 공들여서 만들었으나 사실 이 부분을 지적도 받았다...

왜냐하면 굳이 저렇게 쓸데없이 서버에서 다 처리하지 말고 일부분은 에러메시지를 공통적으로 적용해도 되기 때문이다...

profile
코린이

0개의 댓글