728x90
필요 패키지: Flask (서버), pymongo (DB), pyJWT(토큰생성- 로그인 후 사이트에 일정시간동안 로그인이 지속되게하는거 같은 자유이용권 같은 토큰)
파이참 기준 - 세팅에 TEMPLATE LANGUAGE 검색해서 jinja2 선택
Bulma - Bulma는 순수한 CSS 프레임워크
https://bulma.io/documentation/
Bulma: Free, open source, and modern CSS framework based on Flexbox
Bulma is a free, open source CSS framework based on Flexbox and built with Sass. It's 100% responsive, fully modular, and available for free.
bulma.io
회원가입시 필요한 정보
- 해시함수 - 해시함수 SHA256은 어떤 길이의 입력값을 넣어도 항상 256바이트의 결과값이 나옴
- JWT - JSON Web Token의 줄임말로, JSON 객체를 사용해 정보를 안정성 있게 전달하는 웹표준
.toggleClass
// 선택한 요소에 클래스(Class) 값을 넣었다 뺐다 할 수 있습니다.
function toggle_sign_up() {
$("#sign-up-box").toggleClass("is-hidden")
$("#div-sign-in-or-up").toggleClass("is-hidden")
$("#btn-check-dup").toggleClass("is-hidden")
$("#help-id").toggleClass("is-hidden")
$("#help-password").toggleClass("is-hidden")
$("#help-password2").toggleClass("is-hidden")
}
***회원가입
- 정규표현식
// 정규표현식, 아이디 & 비밀번호
function is_nickname(asValue) {
var regExp = /^(?=.*[a-zA-Z])[-a-zA-Z0-9_.]{2,10}$/;
// (?=.*[a-zA-Z]) - a-z 혹은 A-Z가 꼭 있어야하고
// [-a-zA-Z0-9_.] - 나머지는 a-z, A-Z, 0-9, _, . 까지 있어도 되고
// {2,10} 최소 2자리에서 최대 10자리 까지 이다.
return regExp.test(asValue);
}
function is_password(asValue) {
var regExp = /^(?=.*\d)(?=.*[a-zA-Z])[0-9a-zA-Z!@#$%^&*]{8,20}$/;
return regExp.test(asValue);
}
- 아이디 중복체크 (클라이언트)
function check_dup() {
// input 값 받기
let username = $("#input-username").val()
console.log(username)
// input 값이 아무것도 없을경우
if (username == "") {
$("#help-id").text("아이디를 입력해주세요.").removeClass("is-safe").addClass("is-danger")
$("#input-username").focus()
return;
}
// input값을 위에서 만든 정규표현식 id에 넣었는데 원하는 아이디 형식이 아닐경우
if (!is_nickname(username)) {
$("#help-id").text("아이디의 형식을 확인해주세요. 영문과 숫자, 일부 특수문자(._-) 사용 가능. 2-10자 길이").removeClass("is-safe").addClass("is-danger")
$("#input-username").focus()
return;
}
// 그 외에 아이디 생성이 가능할때
$("#help-id").addClass("is-loading")
$.ajax({
type: "POST",
url: "/sign_up/check_dup",
data: {
username_give: username
},
success: function (response) { // db에 있는 아이디 일 경우
// 아이디가 이미 db에 있는지 체크
if (response["exists"]) {
$("#help-id").text("이미 존재하는 아이디입니다.").removeClass("is-safe").addClass("is-danger")
$("#input-username").focus()
} else { // 없는경우, .addClass("is-success")를 추가해서, 회원가입전에 중복확인이 성공적인지 체크가 가능
$("#help-id").text("사용할 수 있는 아이디입니다.").removeClass("is-danger").addClass("is-success")
}
$("#help-id").removeClass("is-loading")
}
});
}
- 아이디 중복체크 (서버,DB)
@app.route('/sign_up/check_dup', methods=['POST'])
def check_dup():
# id 중복확인
username_receive = request.form['username_give'] #request form으로 username을 받고
# bool 값을 사용해서, db에 username이 있는지 체크
exists = bool(db.users.find_one({"username": username_receive}))
# bool 값을 넘겨줘서 있다 없다를 체크 가능
return jsonify({'result': 'success', 'exists': exists})
- 회원가입 기능 (클라이언트)
function sign_up() {
// input 값 받아오기
let username = $("#input-username").val()
let password = $("#input-password").val()
let password2 = $("#input-password2").val()
console.log(username, password, password2)
// 아이디의 형식, 중복체크 검사
if ($("#help-id").hasClass("is-danger")) {
alert("아이디를 다시 확인해주세요.")
return;
} else if (!$("#help-id").hasClass("is-success")) {
alert("아이디 중복확인을 해주세요.")
return;
}
// 비밀번호 검사
// 비밀번호가 빈칸인지
if (password == "") {
$("#help-password").text("비밀번호를 입력해주세요.").removeClass("is-safe").addClass("is-danger")
$("#input-password").focus()
return;
} else if (!is_password(password)) { //비밀번호가 정규식을 통과했는지
$("#help-password").text("비밀번호의 형식을 확인해주세요. 영문과 숫자 필수 포함, 특수문자(!@#$%^&*) 사용가능 8-20자").removeClass("is-safe").addClass("is-danger")
$("#input-password").focus()
return
} else {
$("#help-password").text("사용할 수 있는 비밀번호입니다.").removeClass("is-danger").addClass("is-success")
}
if (password2 == "") {
$("#help-password2").text("비밀번호를 입력해주세요.").removeClass("is-safe").addClass("is-danger")
$("#input-password2").focus()
return;
} else if (password2 != password) {
$("#help-password2").text("비밀번호가 일치하지 않습니다.").removeClass("is-safe").addClass("is-danger")
$("#input-password2").focus()
return;
} else {
$("#help-password2").text("비밀번호가 일치합니다.").removeClass("is-danger").addClass("is-success")
}
// 위의 모든 검사를 통과하면 서버에 회원가입 양식을 보냄
$.ajax({
type: "POST",
url: "/sign_up/save",
data: {
username_give: username,
password_give: password
},
// 서버로부터 회원가입 ok 라는 답변을 받고, 다음 페이지로 넘어감
success: function (response) {
alert("회원가입을 축하드립니다!")
window.location.replace("/login")
}
});
}
- 회원가입 기능 (서버)
@app.route('/sign_up/save', methods=['POST'])
def sign_up():
# 회원가입
# 아이디 비밀번호 받아옴
username_receive = request.form['username_give']
password_receive = request.form['password_give']
# 비밀번호에는 sha256이라는 해시함수 이용해서 암호화
password_hash = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()
# db에 회원가입 정보를 넘겨줌
doc = {
"username": username_receive, # 아이디
"password": password_hash, # 비밀번호
"profile_name": username_receive, # 프로필 이름 기본값은 아이디
"profile_pic": "", # 프로필 사진 파일 이름
"profile_pic_real": "profile_pics/profile_placeholder.png", # 프로필 사진 기본 이미지
"profile_info": "" # 프로필 한 마디
}
db.users.insert_one(doc)
return jsonify({'result': 'success'})
- 로그인 기능 (클라이언트)
function sign_in() {
// id와 비밀번호 input 가져오기
let username = $("#input-username").val()
let password = $("#input-password").val()
// id 와 비밀번호가 빈값인지 검사.
if (username == "") {
$("#help-id-login").text("아이디를 입력해주세요.")
$("#input-username").focus()
return;
} else {
$("#help-id-login").text("")
}
if (password == "") {
$("#help-password-login").text("비밀번호를 입력해주세요.")
$("#input-password").focus()
return;
} else {
$("#help-password-login").text("")
}
// 검사를 통과했을경우, 서버에 아이디와 비밀번호를 보내줌
$.ajax({
type: "POST",
url: "/sign_in",
data: {
username_give: username,
password_give: password
},
// 아이디와 비밀번호가 성공적으로 있을경우, 유저에게 토큰지급
success: function (response) {
if (response['result'] == 'success') {
$.cookie('mytoken', response['token'], {path: '/'});
window.location.replace("/")
} else {
alert(response['msg'])
}
}
});
}
- 로그인 기능 (서버)
@app.route('/sign_in', methods=['POST'])
def sign_in():
# 로그인, 아이디와 비밀번호를 클라로부터 가져옴
username_receive = request.form['username_give']
password_receive = request.form['password_give']
# 회원가입할때, 비밀번호는 해쉬함수로 암호화 했기때문에
# 로그인할때도 똑같이 암호화해서 db에서 찾아준다
pw_hash = hashlib.sha256(password_receive.encode('utf-8')).hexdigest()
result = db.users.find_one({'username': username_receive, 'password': pw_hash})
# 만약 db 안에 있을경우 = 로그인 성공
if result is not None:
# 토큰 정보입력 누구한테 얼마동안 발행할지
payload = {
'id': username_receive,
'exp': datetime.utcnow() + timedelta(seconds=60 * 60 * 24) # 로그인 24시간 유지
}
# 토큰 발행 - SECRET_KEY 역시 암호화 한번 해주는거임
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return jsonify({'result': 'success', 'token': token})
# 찾지 못하면
else:
return jsonify({'result': 'fail', 'msg': '아이디/비밀번호가 일치하지 않습니다.'})
- 메인페이지가 사용자 알고있기 (서버)
@app.route('/')
def home():
token_receive = request.cookies.get('mytoken')
try:
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
user_info = db.users.find_one({"username": payload["id"]})
return render_template('index.html', user_info=user_info)
except jwt.ExpiredSignatureError:
return redirect(url_for("login", msg="로그인 시간이 만료되었습니다."))
except jwt.exceptions.DecodeError:
return redirect(url_for("login", msg="로그인 정보가 존재하지 않습니다."))
- 포스팅 (클라이언트)
function post() {
let comment = $("#textarea-post").val()
let today = new Date().toISOString()
$.ajax({
type: "POST",
url: "/posting",
data: {
comment_give: comment,
date_give: today
},
success: function (response) {
// 포스팅에 성공하면 모달의 active 클래스를 지워준다
$("#modal-post").removeClass("is-active")
window.location.reload()
}
})
}
- 포스팅 (서버)
@app.route('/posting', methods=['POST'])
def posting():
# 토큰정보는 언제든지 쿠키를 사용해서 가져올수 있음
token_receive = request.cookies.get('mytoken')
try:
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
# 토큰에서 가져온것으로 페이로드를 생성하고, 그 안에 id 를 통해 유저정보를 알수있다.
user_info = db.users.find_one({"username": payload["id"]})
# 추가적으로 코멘트, 작성날짜를 받아와서
comment_receive = request.form["comment_give"]
date_receive = request.form["date_give"]
# db에 넣어줌
doc = {
"username": user_info["username"],
"profile_name": user_info["profile_name"],
"profile_pic_real": user_info["profile_pic_real"],
"comment": comment_receive,
"date": date_receive
}
db.posts.insert_one(doc)
return jsonify({"result": "success", 'msg': '포스팅 성공'})
except (jwt.ExpiredSignatureError, jwt.exceptions.DecodeError):
return redirect(url_for("home"))
728x90
'Sparta > 스파르타코딩 웹개발 종합반' 카테고리의 다른 글
웹개발 종합반 프로젝트 - 06 뉴스크롤링(네이버뉴스) (0) | 2022.03.13 |
---|---|
웹개발 종합반 프로젝트 - 05 진행상황&로그인&뉴스크롤링 (0) | 2022.03.13 |
종합반 플러스 - 3주차 - 네이버API, 셀레니움 (0) | 2022.03.07 |
웹개발 종합반 프로젝트 - 04 날씨&즐겨찾기 (0) | 2022.03.07 |
웹개발 종합반 프로젝트 - 02 뉴스 API (0) | 2022.03.02 |