개발자
저는 컴퓨터공학과 학생이지만 개발이 처음입니다. 프론트엔드를 맡아 리액트 네이티브 앱을 개발하는 중입니다. 기초 지식은 있지만 학교 수업만 들어봤기 때문에 실제로 서비스를 어떻게 만드는지는 몰라, 이번 프로젝트에서는 사실상 GPT가 다 짜줬다고 해도 무방한 정도였어요. 프로젝트가 거의 다 끝나가는데, 백에서 비밀번호에 암호화를 걸면서 수정사항이 생겼습니다. if (existingProfile.password !== profile.oldPassword) { Alert.alert('비밀번호 오류', '기존 비밀번호가 올바르지 않습니다.'); return; } 기존에는 위와 같이 단순하게 비교를 했었는데, 백에서 암호화가 되어버려서 저런 단순한 로직을 사용할 수 없게 되었습니다. 대신 백에서 currentPassword(클라이언트에서 입력받은 비밀번호), getPassword함수(암호화되지 않은 사용자 계정의 기존 비밀번호를 받아오는 함수)를 bcrypt를 이용해서 알아서 다 처리하도록 코드를 다 짜주셨다고 하더라고요. 백엔드 코드는 사진으로 올려두었는데, if (passwordEncoder.matches(currentPassword, user.getPassword()))를 통해서 두 비밀번호가 일치하는 경우에만 정보가 수정되도록 코드가 작성되어 있습니다. 로직은 충분히 이해가 가는데, 이를 프론트엔드 코드에 어떻게 적용해야하는지 전혀 모르겠습니다. 구글링을 어떻게 해야 이런 경우의 풀이가 나오는지도 모르겠고, 찾아봐도 백엔드에서 암호화를 하는 방법이나 해시를 하는 방법 같은 것만 나오네요. 이 문제를 해결하기 위해 일주일 내내 노트북만 붙잡고 있었는데 멘탈만 부서지고, 코드는 아무것도 나아지지 않았습니다. 부디 많은 조언과 도움 부탁드립니다.
1import React, { useState, useEffect } from 'react';
2import { View, TextInput, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, Keyboard, Alert, ScrollView } from 'react-native';
3import AsyncStorage from '@react-native-async-storage/async-storage';
4import DateTimePicker from '@react-native-community/datetimepicker';
5import { API } from '../../config'
6
7export default function EditProfileScreen({ navigation }) {
8 const [profile, setProfile] = useState({
9 oldPassword: '',
10 newPassword: '',
11 confirmPassword: '',
12 nickname: '',
13 department: '',
14 dateOfBirth: new Date(),
15 });
16
17 const [showDatePicker, setShowDatePicker] = useState(false);
18
19 useEffect(() => {
20 const loadProfile = async () => {
21 try {
22 const profileData = await AsyncStorage.getItem('profile');
23 if (profileData) {
24 const savedProfile = JSON.parse(profileData);
25 setProfile(prevProfile => ({
26 ...prevProfile,
27 nickname: savedProfile.nickname || '',
28 studentId: savedProfile.studentId || '',
29 department: savedProfile.department || '',
30 dateOfBirth: savedProfile.dateOfBirth ? new Date(savedProfile.dateOfBirth) : new Date(),
31 }));
32 }
33 } catch (error) {
34 console.error('프로필 로드 실패:', error);
35 }
36 };
37 loadProfile();
38 }, []);
39
40 const isSaveButtonDisabled = !profile.oldPassword;
41
42 const updateUserInfo = async () =>{
43 const userToken = await AsyncStorage.getItem('userToken');
44 const requestBody = {
45 usersDTO: {
46 nickName: profile.nickname,
47 password: profile.newPassword || null,
48 birthday: profile.dateOfBirth.toISOString(),
49 },
50 userAuthenticationDTO: {
51 major: profile.department,
52 },
53 };
54 try {
55 const response = await fetch(`${API.USER}/mypage/edit_userInfo`, {
56 method: 'PUT',
57 headers: {
58 'Authorization': `Bearer ${userToken}`,
59 'Content-Type': 'application/json',
60 },
61 body: JSON.stringify(requestBody),
62 });
63
64 if (!response.ok) {
65 throw new Error('Network response was not ok');
66 }
67
68 const data = await response.json();
69 console.log('Profile updated successfully:', data);
70 Alert.alert('저장 완료', '프로필 정보가 성공적으로 업데이트되었습니다.');
71 navigation.goBack(); // 성공 후 이전 화면으로 돌아가기
72 } catch (error) {
73 console.error('Failed to update profile:', error);
74 Alert.alert('오류', '프로필 업데이트 중 문제가 발생했습니다.');
75 }
76 }
77
78 const handleSave = async () => {
79
80 if (profile.newPassword.length!= 0 && profile.newPassword.length < 10) {
81 Alert.alert('비밀번호 오류', '비밀번호는 최소 10자리 이상이어야 합니다.');
82 return;
83 }
84
85 if (profile.newPassword !== profile.confirmPassword) {
86 Alert.alert('비밀번호 오류', '새 비밀번호와 재입력한 비밀번호가 일치하지 않습니다.');
87 return;
88 }
89
90 try {
91 const existingProfileData = await AsyncStorage.getItem('profile');
92 const existingProfile = existingProfileData ? JSON.parse(existingProfileData) : {};
93
94 if (existingProfile.password !== profile.oldPassword) {
95 Alert.alert('비밀번호 오류', '기존 비밀번호가 올바르지 않습니다.');
96 return;
97 }
98 await updateUserInfo();
99
100 //await AsyncStorage.setItem('profile', JSON.stringify(updatedProfile));
101 Alert.alert('저장 완료', '프로필 정보가 저장되었습니다.');
102 navigation.goBack();
103 } catch (error) {
104 console.error('프로필 저장 실패:', error);
105 }
106 };
107
108 const handleDateChange = (event, selectedDate) => {
109 setShowDatePicker(false);
110 if (selectedDate) {
111 setProfile({ ...profile, dateOfBirth: selectedDate });
112 }
113 };
커리어리 AI 봇
GPT가 달아주는 답변입니다.
2024년 08월 11일
비밀번호를 클라이언트 부분에서 비교하지 않고, 서버에서 전체적인 검증을 마친 후에 결과만 반환하는 방식으로 처리하면 됩니다. 서버단에서 currentPassword와 hashed password의 일치여부를 확인하기 때문에, 프론트엔드에서는 이제 검증된 사용자 정보를 화면으로 전달해주기만 하면 됩니다. 클라이언트가 변조된 데이터를 보내게 되더라도, 해시된 비밀번호가 아니므로 서버단에서 매치되지 않아 요청은 실패하게 됩니다. 변경 사항을 적용한 updateUserInfo 함수는 아래와 같습니다: ```javascript const updateUserInfo = async () => { const userToken = await AsyncStorage.getItem('userToken'); const requestBody = { usersDTO: { oldPassword: profile.oldPassword, nickName: profile.nickname, password: profile.newPassword || null, birthday: profile.dateOfBirth.toISOString(), }, userAuthenticationDTO: { major: profile.department, }, }; try { const response = await fetch(`${API.USER}/mypage/edit_userInfo`, { method: 'PUT', headers: { 'Authorization': `Bearer ${userToken}`, 'Content-Type': 'application/json', }, body: JSON.stringify(requestBody), }); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); if (data.success){ Alert.alert('저장 완료', '프로필 정보가 성공적으로 업데이트되었습니다.'); navigation.goBack(); // 성공 후 이전 화면으로 돌아가기 } else{ Alert.alert('비밀번호 오류', '기존 비밀번호가 올바르지 않습니다.'); } } catch (error) { console.error('Failed to update profile:', error); Alert.alert('오류', '프로필 업데이트 중 문제가 발생했습니다.'); } }; ``` 위 코드에서는 백엔드에서 암호화된 비밀번호와 사용자가 입력한 기존 비밀번호를 둘다 서버로 보내고, 서버에서 검증된 경우에만 프로필 정보를 업데이트하게 됩니다. 서버에서 반환하는 응답값을 확인하여 일치하지 않는 경우 사용자에게 알림이 출력되도록 처리합니다. 이렇게 변경한다면 클라이언트 부분에서 패스워드를 직접 처리하는 로직을 제거할 수 있습니다.
지금 가입하면 모든 질문의 답변을 볼 수 있어요!