위에 적힌 것으로 즉, 총 10종류의 경우에 대해 각각의 메시지를 출력한다.
하지만 if 문으로 위에서부터 내려오면서 작동하기에 맨 먼저 걸린것에 대한 알림 하나만을 띄우게 된다.
암호화는 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': '양식에 맞게 입력해 주세요.'}) # 위의 모든 과정과 맞지 않으면 발생
참고 링크 : 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)
회원가입 시 중복값 및 여러가지 예외사항들을 처리를 한다.
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': '아이디 작성시 양식에 맞게 다시 입력해 주세요 !'})
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': '이미 사용중인 아이디가 있습니다 !'})
위의 예외사항 들 중에서 아무것도 걸리지 않고 양식도 맞게 입력 되었으면 회원가입을 완료한다.
하지만 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': '양식에 맞게 입력해 주세요.'})
// 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']) // 회원가입 실패시 메시지 출력 } } }) }
// 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') } }); }
처음 입력한 비밀번호와 확인용 비밀번호가 일치하는지 확인해서 경고문구를 나타내고 감추는 부분
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') } }); }
회원가입 부분에서 꽤나 공들여서 만들었으나 사실 이 부분을 지적도 받았다...
왜냐하면 굳이 저렇게 쓸데없이 서버에서 다 처리하지 말고 일부분은 에러메시지를 공통적으로 적용해도 되기 때문이다...