코딩기록
Java converter 사용 시 주의해야 할 점 - 회원가입 및 로그인 구현 관련 본문
- 현재 직장인들을 위한 커뮤니티 개발 팀에서 계정 백엔드 개발을 담당하고 있다.
- Converter를 적용하여 db에 비밀번호를 저장할 경우 자동으로 BCryptPasswordEncoder를 이용하여 저장되게 하였다.
- 그런데 converter를 구현한지 얼마 되지 않아, 팀원분께서 두번째 로그인을 시도할 때부터 로그인이 되지 않는다는 노티를 해 주셨다.
- 원인을 찾아본 결과, Converter 의 문제였다.
Converter를 적용하여 db에 비밀번호를 저장할 경우 자동으로 BCryptPasswordEncoder를 이용하여 저장되게 하였는데, 그 전에 구현한 기능 중 유저가 로그인 시 해당 로그인 유저의 최근방문시점 및 방문횟수를 업데이트 하도록 구현한 것이 있었다.
기존에 최근방문시점 및 방문횟수를 아래처럼 jpa가 수정하도록 하였는데, 이경우 모든 컬럼에 대해 update문이 날라가서 User 엔티티의 @convert에 의해 이미 인코딩되어 저장되어 있는 password가 한번더 인코딩되어 저장되는 문제였던 것이다. - 해결 방법
- 첫번째 시도
최근방문시점 및 방문 횟수를 직접 작성한 쿼리문으로 업데이트하도록 수정했다.
@Modifying
@Query(value = "UPDATE users SET number_of_visits = number_of_visits+1 WHERE login_id = :loginId", nativeQuery = true)
void mIncreaseNumberOfVisitsByLoginId(String loginId);
@Modifying
@Query(value = "UPDATE users SET last_visited_at = NOW() WHERE login_id = :loginId", nativeQuery = true)
void mUpdateLastVisitedAt(String loginId);
- 문제점: 유저 엔티티 변경하는 모든 경우에 jpa를 사용하지 못하고 쿼리문을 작성해야 해서 부적절했다.
- 두번째 시도
User 엔티티의 비밀번호 필드에 updatable = false 를 붙여 비밀번호 수정을 jpa에서 못하게 하고, 유저가 직접 비밀번호 변경을 요청할 때에는 직접 작성한 update 쿼리문을 날리도록 했다.
@Convert(converter = PasswordEncryptConverter.class)
@Column(name = "password", nullable = false, updatable = false)
private String password;
- 문제점: 회원가입 시에는 자동으로 인코딩 되나, 비밀번호 수정 요청에는 직접 백엔드 단에서 BCryptPasswordEncoder로 인코딩하여 db에 넘겨주어야 했다. 즉, 회원가입 시와 비밀번호 수정 요청때 비밀번호를 저장하는 방법이 일관성이 없었다.
- 세번째 시도(해결)
일관성 유지할 수 있도록 converter를 없애고, 비밀번호를 저장하는 상황에는 bCryptPasswordEncoder 호출하여 비밀번호 인코딩하도록 수정했다. - 느낀 점
모든 데이터를 일괄적으로 바꾸는 기능을 사용할 경우 이 기능이 미치는 영향을 면밀하게 예측해 보아야 겠다고 생각했다.