계정관리 기능
백앤드
class UserVerifyView(APIView):
authentication_classes = [JWTAuthentication]
def post(self, request):
correct_password = re.compile(
"^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$")
password_input = correct_password.match(request.data["password"])
if request.data["username"] == "" or request.data["password"] == "":
return Response({"message": "아이디 또는 비밀번호 값을 제대로 입력해주세요."}, status=status.HTTP_400_BAD_REQUEST)
else:
if password_input == None:
return Response({"message": "비밀번호 형식에 맞게 작성해주세요."}, status=status.HTTP_400_BAD_REQUEST)
else:
user = authenticate(username=request.data["username"], password=request.data["password"])
if request.user == user:
user = UserModel.objects.get(username=request.data["username"])
user_data = UserSerializer(user)
return Response(user_data.data, status=status.HTTP_200_OK)
else:
return Response({"message": "존재하지 않는 사용자입니다."}, status=status.HTTP_404_NOT_FOUND)
- 비밀번호 정규표현식은 회원가입을 할 때 정규표현식을 사용해 받고 있지만, 해당 기능을 사용하면서 사용자가 어떤 부분이 틀렸는지 최대한 상세히 알 수 있도록 하고 싶어 사용하였다.
authenticate
를 사용해 현재 로그인한 사용자가 계정관리 페이지에서 입력한 아이디와 비밀번호를 가진 사용자와 일치하는지 확인하였다.
- 만약 현재 로그인한 사용자가 인증한 사용자와 일치한다면 쿼리를 날려 데이터를 찾아 프론트로 보내주었다.
class accountUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = UserModel
fields = ["username", "password", "fullname", "email",
"phone", "birthday", "region", "join_date"]
extra_kwargs = {
"password": {"write_only": True},
}
def validate(self, data):
correct_phone = re.compile("(010)-\d{4}-\d{4}")
phone_input = correct_phone.match(data.get("phone", ""))
if data.get("username"):
if not len(data.get("username", "")) >= 6:
raise serializers.ValidationError(
detail={"error": "username의 길이는 6자리 이상이어야 합니다."})
if not data.get("email", "").endswith(EMAIL):
raise serializers.ValidationError(
detail={"error": "네이버, 구글, 카카오, 다음, 네이트, 아웃룩 이메일만 가입할 수 있습니다."})
if phone_input == None:
raise serializers.ValidationError(
detail={"error": "전화번호는 010-0000-0000 형식으로 작성해주시기 바랍니다."})
return data
def update(self, instance, validated_data):
for key, value in validated_data.items():
if key == "password":
instance.set_password(value)
continue
setattr(instance, key, value)
instance.save()
return instance
- 원래는 회원가입에서 쓰던 시리얼라이저를 같이 쓸 계획이었다. 하지만 비밀번호 정규식이 적용되어 있었고, 정보 수정을 위해 지울 수는 없었다. 정규식이 없으면 비밀번호를 1234로 쳐도 회원가입이 되기 때문이다.
- 프론트 화면에 비밀번호에 대한 요구사항이 있긴 하지만 사용자가 꼭 그 값에 따라 입력한다는 보장이 없었기 때문이다.
- 회원정보 수정 view에는 수정할 정보를 partial=True로 받아 수정하고 싶은 값만 수정할 수 있다.
- 그것에 맞게 새로운 시리얼라이저를 만들고 비밀번호에 대한 정규표현식을 없애주어 비밀번호 데이터가 넘어오지 않더라도 수정할 수 있도록 해주었다.
프론트앤드
async function searchUser() {
const userData = {
username: document.getElementById("checkUsername").value,
password: document.getElementById("checkPassword").value
}
const response = await fetch(`${backend_base_url}user/verification/`, {
headers: {
Accept: "application/json",
'Content-type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("access")
},
method: "POST",
body: JSON.stringify(userData)
})
verification_json = await response.json()
if (response.status == 200) {
const popup = document.getElementById("popup")
popup.style.visibility = "visible"
document.getElementById("accountUsername").value = verification_json.username
document.getElementById("accountFullname").value = verification_json.fullname
document.getElementById("accountEmail").value = verification_json.email
document.getElementById("accountPhone").value = verification_json.phone
document.getElementById("accountBirthday").value = verification_json.birthday
document.getElementById("accountRegion").value = verification_json.region
} else {
alert(verification_json["message"])
const popup = document.getElementById("popup")
popup.style.visibility = "hidden"
}
}
- 백앤드에서 요구하는 데이터를 찾아와 보내주었다.
- status code를 사용해 어떤 반응을 보여주어야 하는지 설정하였다. 백앤드에서 작성한 message를 받아와 사용자에게 alert를 통해 보여주어 어떤 조치를 취해야 하는지 알려주었다.
response.status == 200
에 있는 부분은 사용자가 권한 인증을 마치고 나면 모달을 띄워 정보 수정을 할 수 있게 하고 싶어 작성하였다. 해당 코드들로 인해 사용자가 모달을 볼 때 본인이 작성했던 정보들을 확인할 수 있다.
- 비밀번호의 값은 제거해 주었다. 왜냐하면 백앤드에서 정보가 넘어올 때 해싱된 값이 넘어오고 해당 부분을 수정하지 않고 넘기면 404 에러가 떴기 때문이다.
async function changeAccount() {
let changedData
if (document.getElementById("accountPassword").value) {
changedData = {
username: document.getElementById("accountUsername").value,
password: document.getElementById("accountPassword").value,
fullname: document.getElementById("accountFullname").value,
email: document.getElementById("accountEmail").value,
phone: document.getElementById("accountPhone").value,
birthday: document.getElementById("accountBirthday").value,
region: document.getElementById("accountRegion").value
}
} else {
changedData = {
username: document.getElementById("accountUsername").value,
fullname: document.getElementById("accountFullname").value,
email: document.getElementById("accountEmail").value,
phone: document.getElementById("accountPhone").value,
birthday: document.getElementById("accountBirthday").value,
region: document.getElementById("accountRegion").value
}
}
const response = await fetch(`${backend_base_url}user/`, {
headers: {
Accept: "application/json",
'Content-type': 'application/json',
'Authorization': 'Bearer ' + localStorage.getItem("access")
},
method: "PUT",
body: JSON.stringify(changedData)
})
account_response = response.json()
if (response.status == 200) {
alert("회원정보 수정이 완료되었습니다.")
window.location.replace(`${frontend_base_url}index.html`)
} else {
alert(account_response.data)
}
}
- 해당 부분을 작성할 때도 비밀번호가 엄청난 문제였다. 그래서 비밀번호를 비워준 김에 비밀번호를 입력한 값과 아닌 값을 나누어 백앤드로 보내주었다.
- 사용자가 꼭 비밀번호를 바꾸기 위해서 계정관리 페이지에 들어가는 것은 아니기 때문이다.
- 해당 부분은 모달에서 수정하기 버튼을 누르게 되면 실행되는 함수이다.