회원가입과 비밀번호 암호화
그동안 회원가입이 없었기 때문에 data.sql 로 회원 정보를 넣고 그걸 바탕으로 로그인 로직을 수행했었다.
이제 회원가입 기능을 만들기 때문에 data.sql 은 사용하지 않으니 삭제하거나
yml 파일에서 sql.init.mode : never 로 바꿔주자.
비밀번호는 개인정보이므로 암호화해서 처리해야 한다.
기본 설정
spring security 라이브러리를 이용하여 암호화를 해보자.
아래처럼 의존성을 추가해준다.
build.gradle
implementation 'org.springframework.security:spring-security-crypto'
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
AuthController
Signup 객체에 회원가입 정보를 받아서 저장하는 컨트롤러를 작성한다.
@PostMapping("/auth/signup")
public void signup(@RequestBody Signup signup) {
authService.signup(signup);
}
Signup
회원가입 정보를 담는 객체이다. 필요하다면 여기에 검증 기능도 넣으면 좋을것이다.
@Getter
@NoArgsConstructor
public class Signup {
private String email;
private String name;
private String password;
@Builder
public Signup(String name, String password, String email) {
this.email = email;
this.name = name;
this.password = password;
}
}
AuthService
하는김에 중복 체크도 하는 회원가입 로직을 만든다.
중복 체크 후 비밀번호를 암호화해서 저장한다.
@Service
@RequiredArgsConstructor
public class AuthService {
private final UserRepository userRepository;
private final PasswordEncoder encoder;
@Transactional
public void signup(Signup signup) {
Optional<User> userOptional = userRepository.findByEmail(signup.getEmail());
if (userOptional.isPresent()) {
throw new AlreadyExistEmailException();
}
String encryptedPassword = encoder.encrypt(signup.getPassword());
User user = User.builder()
.email(signup.getEmail())
.name(signup.getName())
.password(encryptedPassword)
.build();
userRepository.save(user);
}
}
PasswordEncoder
재사용성을 위해 PasswordEncoder 를 만들어서 여기서 암호화 관련 메서드를 처리한다.
@Component
public class PasswordEncoder {
private static final PasswordEncoder encoder = new PasswordEncoder(
16,
8,
1,
32,
64);
public String encrypt(String rawPassword) {
return encoder.encode(rawPassword);
}
public boolean matches(String rawPassword, String encryptedPassword) {
return encoder.matches(rawPassword, encryptedPassword);
}
}
AlreadyExistEmailException
중복 회원일 시 발생하는 커스텀 예외
public class AlreadyExistEmailException extends DunpleException {
private static String MESSAGE = "이미 가입된 이메일입니다.";
public AlreadyExistEmailException() {
super(MESSAGE);
}
@Override
public int getStatusCode() {
return 400;
}
}
UserRepository
중복체크를 위해 Email 로 가입된 회원이 존재하는지 확인하는 메서드를 만든다.
Optional<User> findByEmail(String Email);
테스트
AuthSerivceTest
AuthService 의 회원가입 성공, 실패 테스트를 작성한다.
@DisplayName("회원가입 성공")
@Test
void signup() {
// given
Signup signup = Signup.builder()
.email("hyukkind@naver.com")
.name("midcon")
.password("1234")
.build();
// when
authService.signup(signup);
User user = userRepository.findByEmail("hyukkind@naver.com")
.orElseThrow(() -> new InvalidSigninInformationException());
// then
assertEquals(1, userRepository.count());
assertEquals("hyukkind@naver.com", user.getEmail());
assertEquals("midcon", user.getName());
assertTrue(encoder.matches("1234", user.getPassword()));
}
@DisplayName("중복된 이메일로 회원가입 시 예외가 발생")
@Test
void signup2() {
// given
User user = User.builder()
.email("hyukkind@naver.com")
.name("mika")
.password("1234")
.build();
userRepository.save(user);
Signup signup = Signup.builder()
.email("hyukkind@naver.com")
.name("midcon")
.password("1234")
.build();
// expected
assertThrows(AlreadyExistEmailException.class,
() -> authService.signup(signup));
}

테스트는 성공하고 의도한대로 동작함을 알 수 있다.
AuthControllerTest
AuthController 의 회원가입 성공, 실패 테스트를 작성한다.
@DisplayName("회원가입 성공")
@Test
void signup() throws Exception {
// given
Signup signup = Signup.builder()
.email("hyukkind@naver.com")
.name("midcon")
.password("1234")
.build();
String json = objectMapper.writeValueAsString(signup);
// expected
mockMvc.perform(post("/auth/signup")
.content(json)
.contentType(APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print());
}
@DisplayName("회원가입 실패")
@Test
void signup2() throws Exception {
// given
User user = User.builder()
.email("hyukkind@naver.com")
.name("midcon")
.password(encoder.encrypt("1234"))
.build();
userRepository.save(user);
Signup signup = Signup.builder()
.email("hyukkind@naver.com")
.name("mika")
.password("1234")
.build();
String json = objectMapper.writeValueAsString(signup);
// expected
mockMvc.perform(post("/auth/signup")
.content(json)
.contentType(APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andDo(print());
}

테스트는 성공하고 원하는대로 동작함을 알 수 있다.
'API 만들어 보기 > 게시판 API' 카테고리의 다른 글
[API 인증] JWT 를 이용한 인증 2 (0) | 2023.10.07 |
---|---|
[API 인증] JWT 를 이용한 인증 1 (0) | 2023.10.07 |
[API 인증] 쿠키를 통한 인증 및 검증 (0) | 2023.10.03 |
[API 인증] DB를 통한 토큰 발급 및 검증 2 (0) | 2023.10.02 |
[API 인증] DB를 통한 토큰 발급 및 검증 1 (0) | 2023.10.01 |