gi_dor

암호화된 비밀번호 변경 (비동기) 본문

Back_End/SpringBoot

암호화된 비밀번호 변경 (비동기)

기돌 2024. 4. 24. 18:05
728x90

 

암호화 되어있는 비밀번호를 변경해보겠습니다

<!-- 비밀번호 변경 -->
<update id="updatePassword" >
    update USER
    set password = #{password}
    where user_id =  #{id}
</update>
@Mapper
public interface MyPageMapper {  
 void updatePassword(@Param("id") String id, @Param("password") String password);
}

@Param 어노테이션은 매퍼인터페이스의 매개변수에 이름을 지정하는데 사용하는데
XML에서는 해당 파라미터의 이름을 사용하여 쿼리에 값을 전달할 수 있다

기존에는 값이 2개가 넘어가면 Map 도 사용하지 않고 ( 익숙하지 않음 )
parameterType="User" 를 사용해서 User 클래스를 사용했었다.

User 클래스는 사용자의 모든 정보를 포함하는 객체로 비밀번호 변경하는 기능에서
사용자의 아이디와 비밀번호만 필요하기에 새로운 DTO를 만들어 사용하려고 합니다

public class User {

    private Long no;
    private String id;
    private String password;
    private String name;
    private String email;
    private LocalDateTime createdDate;
    private LocalDateTime updatedDate;
    private String tel;
    private String zipCode;
    private String address;
    private String addressDetail;
    private String delYn;
    private Long point;
    private UserGrade userGrade;
    private CouponProduced couponPr;

    public String getFullAddress() {
        return String.format("%s %s %s", zipCode,address,addressDetail);
    }
}
@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class ChangePasswordForm {

    @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[~!@#$%^&*()+|=])[A-Za-z\\d~!@#$%^&*()+|=]{8,16}$"  , message ="알맞은 형식이 아닙니다")
    private String password;

    @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[~!@#$%^&*()+|=])[A-Za-z\\d~!@#$%^&*()+|=]{8,16}$"  , message ="알맞은 형식이 아닙니다")
    private String changePassword;

    @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[~!@#$%^&*()+|=])[A-Za-z\\d~!@#$%^&*()+|=]{8,16}$"  , message ="알맞은 형식이 아닙니다")
    private String confirmNewPassword;
}

정규표현식과 단순하게 사용하기위해 ChangePasswordForm DTO를 만들어 사용하겠습니다

public void updatePassword(String id, ChangePasswordForm form) {

    User user = userMapper.selectUserById(id);
    String originalPassword = user.getPassword();
    if (!passwordEncoder.matches(form.getPassword(), originalPassword)) {
        throw new RuntimeException("비밀번호 불일치");
    }

    //form.setChangePassword(passwordEncoder.encode(form.getChangePassword()));

    myPageMapper.updatePassword(id, passwordEncoder.encode(form.getChangePassword()));
}
  • DB에서 가져온 비밀번호 originalPassword
  • 사용자가 입력한 비밀번호 form.getPassword()

PasswordEncoder인터페이스에 있는 matches ( ) 는 rawPassword (내가 입력한 비밀번호) 가 encodedPassword(주어진 암호화된 비밀번호) 와 일치하는지 확인하는데 사용된다

if (!passwordEncoder.matches(form.getPassword(), originalPassword)) {
    throw new RuntimeException("비밀번호 불일치");
}

passwordEncoder.matchs( 내가입력한 비밀번호 , DB에 암호화되어있는 비밀번호)

void updatePassword(@Param("id") String id, ChangePasswordForm changePasswordForm);

기존에 코드 changePasswordFormString password 로 변경했는데

1. ChangePasswordForm 의 변수들이 3개나 있어서 굳이 코드를 더 늘려서 쓸 필요가 없음
changePasswordForm.getXXXXXX()

2. 암호화 되지 않은 값이기에 service 에서 set 을 사용 해 암호화 해줘야한다

@Service
@RequiredArgsConstructor
public class MyPageService {

    private final PasswordEncoder passwordEncoder;
    private final MyPageMapper myPageMapper;
    private final UserMapper userMapper;
    private final UserService userService;

      public void updatePassword(String id, ChangePasswordForm form) {

        // 사용자 ID를 사용하여 데이터베이스에서 해당 사용자 정보를 가져오기
        User user = userMapper.selectUserById(id);

        // DB에서 가져온 사용자 비밀번호 가져오기
        String originalPassword = user.getPassword();

        // 사용자가 입력한 비밀번호 form.getPassword()
        // DB에서 가져온 비밀번호 originalPassword
        if (!passwordEncoder.matches(form.getPassword(), originalPassword)) {
            throw new RuntimeException("비밀번호 불일치");
        }
        // 암호화 해준 뒤에 값 넣어줘야함
       String newPassword = form.setChangePassword(passwordEncoder.encode(form.getChangePassword()));

        myPageMapper.updatePassword(id, newPassword);
    }

}

@PostMapping("/changePassword")
    @ResponseBody
    public String changePassword(Principal principal,
                                 @Valid ChangePasswordForm form ,
                                 BindingResult errors) {

        // 입력 폼에 유효성 검사 에러가 있을 경우, "fail" 문자열을 반환
        if (errors.hasErrors()) {
           return "fail";
        }

        try {
            // 사용자의 아이디를 principal 객체로 획득
            String id = principal.getName();
            myPageService.updatePassword(id, form);
            return "success";
        } catch (RuntimeException e) {
            e.printStackTrace();
            return "fail";
        }
    }

 

 

 

<tr>
   <th class="table-secondary">비밀번호</th>
   <td colspan="3">
     <button type="button" class="btn btn-secondary" id="passwordButton" onclick="showModal()"> 비밀번호 변경</button>
   </td>
</tr>

......

<!-- modal -->
<div class="modal" tabindex="-1" id="modal-user-password">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">비밀번호 변경</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">

                <div class="form-group mb-3">
                    <div class="row">
                        <div class="col-1"></div>
                        <div class="col-9">
                            <input type="password" class="form-control" id="prev-password" name="password" placeholder="기존 비밀번호" style="margin-bottom: 5px;" />
                            <input type="password" class="form-control" id="new-password" name="changePassword" placeholder="새로운 비밀번호" style="margin-bottom: 5px;"/>
                            <input type="password" class="form-control" id="new-confirm-password" name="confirmNewPassword" placeholder="새로운 비밀번호 재입력" style="margin-bottom: 5px;"/>
                            <div th:errors="${user.password}" class="text-danger"></div>
                            <div id="passwordMatchMessage" class="text-danger2"></div>
                        </div>
                        <div class="col-1"></div>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
                <button type="button" class="btn btn-secondary" onclick="modalPassword()">비밀번호 변경</button>
            </div>
        </div>
    </div>
</div>

https://getbootstrap.kr/docs/5.2/components/modal/

 

모달

Bootstrap JavaScript 모달 플러그인을 사용하여 라이트박스, 사용자 알림 또는 사용자 정의 콘텐츠를 만들 수 있습니다.

getbootstrap.kr

 

Bootstrap JavaScript 모달 플러그인을 사용하여 라이트박스, 사용자 알림 또는 사용자 정의 콘텐츠를 만들 수 있습니다.

 

<script>
    const openModal = document.getElementById('passwordButton');

    function showModal() {
        const myModal = new bootstrap.Modal(document.getElementById('modal-user-password'));
           myModal.show();
    }

</script>

id="passwordButton" 인 버튼 태그에 클릭 이벤트 onclick="showModal() 로 modal 창을 띄웁니다.

 

// 모달창 입력한 값 지우기
function removeText() {
    $('#prev-password').val('');
    $('#new-password').val('');
    $('#new-confirm-password').val('');
}

비밀번호 변경 버튼 클릭시  기존 비밀번호 , 새로운 비밀번호 , 확인 비밀번호 3가지를 비교 하는 작업을하면서
지속적으로 입력한 필드의 값을 지우기 위해 사용되기에 따로 분리해서 removeText() 로 사용

3번 연속 사용되기에 코드의 길이가 길어져서 함수로 만들어서 사용했습니다

 

    let password = $('#prev-password').val();
        let newPassword = $('#new-password').val();
        let confirmNewPassword = $('#new-confirm-password').val();

        // 입력값이 비어 있는지 확인
        if (!password || !newPassword || !confirmNewPassword) {
            alert('비밀번호를  입력하세요.');
            removeText();

            return;
        }

        // 새로운 비밀번호와 확인 비밀번호가 일치하는지 확인
        if (newPassword !== confirmNewPassword) {
            alert('새로운 비밀번호가 일치하지 않습니다.');
            removeText();

            return;
        }
  • 입력한 3개의 필드에 값을 가져온다
  • 각각 변수의 들어있는 값을 비교 해서 공백일시 alert  발생 , 입력필드의 값 삭제
  • 새로운 비밀번호와 , 확인용 비밀번호의 필드에 값을 비교해 일치하지 않을시 alert 와 입력필드의 값 삭제

 

   function modalPassword() {
        let password = $('#prev-password').val();
        let newPassword = $('#new-password').val();
        let confirmNewPassword = $('#new-confirm-password').val();

        // 입력값이 비어 있는지 확인
        if (!password || !newPassword || !confirmNewPassword) {
            alert('비밀번호를  입력하세요.');
            removeText();

            return;
        }

        // 새로운 비밀번호와 확인 비밀번호가 일치하는지 확인
        if (newPassword !== confirmNewPassword) {
            alert('새로운 비밀번호가 일치하지 않습니다.');
            removeText();

            return;
        }

        $.ajax({
            url:'/mypage/changePassword' ,
            type:'post',
            data:{
                password: password,
                changePassword: newPassword,
                confirmNewPassword: confirmNewPassword
            },
            success:function (data) {
                if (data == "success") {
                    alert("비밀번호가 성공적으로 변경되었습니다 ")
                    removeText();

                    // 변경 성공 시 모달 닫기
                    $('#modal-user-password').modal('hide');
                } else {
                    alert('비밀번호 변경에 실패했습니다.');

                    // 모달창 입력한 값 지우기
                    removeText();
                }
            },
            error: function (status , error) {
                alert('서버 오류: ' + error + ', 상태 코드: ' + status);
            }
        });
    };

 

 

 

변경 전 

 

변경 후

728x90