TIL & WIL

회원가입 - 유효성검사 & 암호화

강민승 2022. 10. 25. 23:05

목표: 회원가입페이지를 간단하게 만들어보자!

 

 

사용한 라이브러리

front :  jquery  / backend : python(flask_bcrypt, flask, pymongo)

 

 

javascript , python

//front

function errorMessage(text) {
        document.getElementById("signup_error").innerText =
            text;
        setTimeout(() => {
            document.getElementById("signup_error").innerText = "";
        }, 4000);
    }

    function Signup() {
        let username = $("#username").val();
        let nick = $("#nick").val();
        let password = $("#password").val();
        let idValCheck = /^[a-z0-9]+$/;
        let pwdValCheck = /^[a-zA-Z\\d`~!@#$%^&*()-_=+]{8,24}$/;


        if (username == "") {
            return errorMessage('아이디를 입력해주세요.');
        }
        
        if (username.search(/\s/) != -1) {
            return errorMessage("아이디에 공백이 들어갈 수 없습니다.");
        }
        
        if (!idValCheck.test(username) || username.length < 8) {
            return errorMessage("아이디는 영소문자,숫자로 구성된 8글자 이상으로 조합해서 사용해주세요.")
        }

        if (nick == "") {
            return errorMessage("닉네임을 입력해주세요.");
        }
        
        if (password == "") {
             return errorMessage("비밀번호를 입력해주세요.");
        }
        
        //test() 메서드는 주어진 문자열이 정규 표현식을 만족하는지 판별하고, 그 여부를 true 또는 false로 반환한다.
        //false일때
        if (!pwdValCheck.test(password)) {
            return errorMessage("비밀번호는 영소문자,숫자,특수문자로 구성하여 8글자~24자로 조합해서 사용해주세요.");
        } 
       


        $.ajax({
            type: "POST",
            url: "/user/signup",
            data: {user_id: username, user_pwd: password, user_nick: nick},
            success: function (res) {
                console.log(res);
                if (res.result == "FAIL") {
                    let error_message = (document.getElementById(
                        "signup_error"
                    ).innerText = `이미 존재하는 아이디입니다.`);
                    console.log(error_message);

                } else {
                    alert("회원가입이 완료되었습니다.");
                    window.location.href = "/";
                }
            },
        });

    }

정규식

 

사용한 정규식 리터럴 의미
/^[a-z0-9]+$/ a-z소문자 아무거나,0-9숫자 아무거나 사용할수 있다는 뜻
/^[a-zA-Z\\d`~!@#$%^&*()-_=+]{8,24}$/ 영소문자,숫자,특수문자 8글자 이상 24글자 이하로 사용할 수 있다는 뜻

 

정규식은  아래와 같이 구분이 된다.

/ (http|https|ftp|telnet|news|mms):\/\/[^\"'\s()]+ / i
패턴구분자 시작 찾을 문자의 패턴 패턴구분자 끝 패턴변경자

 

메타문자

다른 언어에서 연산자나 예약어로 쓰이는 문자를 정규 표현식에서는 메타 문자라고 부른다. 문자열의 시작과 끝을 표시하는 메타 문자는 옵션에 따라 줄 단위나 문서 전체를 의미할 수 있다.

 

^ 문자열의 시작
$ 문자열의 종료

 

문자 집합과 특수 문자

이외에도 기본적으로 정의된 문자 집합과 특수 문자를 나타내는 몇가지 이스케이프 문자가 있다.

문자 집합은 대괄호 한 쌍으로 정의되는 문장이며 그 안에는 찾아야 할 문자들이 포함된다. 이때 문자 집합 내부에서 전용으로 사용되는 메타 문자가 있는데 ^는 해당 집합에 포함된 문자들을 검색에서 제외하고, 문자와 문자 사이에 -가 있을 경우 해당하는 문자 코드 범위내의 모든 문자를 포함한다.

대문자를 쓰면 해당 문자 집합을 제외하는 ^ 문자와 동일하다.

 

\b 문자와 공백 사이를 의미 \s 공백 문자
\c 제어 문자를 의미 \t 탭 문자
\d 숫자에 해당하는 유니코드에 대응.
[0-9]와 달리 아랍 문자페르시아 문자 등 다양한 숫자를 포괄
\v 수직 탭
\f 폼 피드 \w 단어 영문자+숫자+_(밑줄) [0-9a-zA-Z_]
\n 개행 문자 \x 16진수 값
\0 8진수 값    

 

 

 

 

정말 진지하게 말하지만 정규식은 조금만 이해하는 것이 건강에 좋은 것 같다. 어느정도 이해하고 구글링을 하자.

 

 

 

#backend

from pymongo import MongoClient
from flask import Flask, render_template, jsonify, request
from flask_bcrypt import Bcrypt, generate_password_hash, check_password_hash


import certifi

ca = certifi.where()
client = MongoClient('mongodb+srv://id:password@cluster0.내주소.mongodb.net/데이터베이스이름?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta
app = Flask(__name__)
bcrypt = Bcrypt(app)


@app.route('/user/signup', methods=['POST'])
def signup():
    # id, password 받아오고 저장
    user_id = request.form['user_id']
    user_pwd = request.form['user_pwd']
    user_nick = request.form['user_nick']
    pw_hash = generate_password_hash(user_pwd)  #비밀번호를 암호화

    # id 중복확인
    if db.user.count_documents({'user_id': user_id}) == 0: #db 
        #db.collection.countDocuments(query, options) - db의 데이터를 카운트해서 반환함.
        
        db.user.insert_one({'user_id': user_id, 'user_pwd': pw_hash,'user_nick':user_nick})
        return jsonify({'result': 'SUCCESS', 'message': 'SIGN UP SUCCESS'})
    else:
        return jsonify({'result': 'FAIL', 'message': 'user_id already exists'})

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)

 

회원가입 이벤트 순서 front/backend 내용
1 front 아이디 비밀번호 닉네임을 적은 후 버튼 클릭
2 front Signup 함수 실행
3 front 유효성 검사(하나라도 false시 return)
4 front backend쪽으로 데이터 전송 
5 backend 데이터 수신 후 비밀번호 암호화
6 backend 서버(pymongo)에 저장 후 response
7 backend result결과로 true면 회원가입, false면 error메시지

 

에러메시지를 html에 뿌려주는 것과 에러메시지를 사라지게하는 것은 중복되는 코드가 예상되기에 함수를 만들어 반복해서 사용했다.

유효성검사를 하는 부분과 비동기처리를 하는 부분을 나눠서 작성하고 싶었지만 하지 못했으나 고민해보고 꼭 해보도록 하자.

또한 회원가입 버튼을 눌렀을 때 중복으로 누르지 못하도록 disabled화 시키는 것과 에러메시지도 수정해야 할 것 같다.

 

다음은 위의 코드가 동작하는 모습을 영상으로 업로드 해보았다.

내용은 로그인을 하고 토큰을 받아 쿠키에 저장 후 쿠키를 확인하는 내용이 함께 담겨있다.