작성자 없음
작성자 정보가 삭제된 글입니다.
해결된 질문
작성
·
1K
·
수정됨
2
보통 암호화하는 클래스들을 static 유틸클래스들로 만들었었는데 이런 static유틸클래스와 @Component를 달아서 사용하는 유틸클래스는 어떤 차이를 만들어낼수있는건가요..?
제가 생각했을땐 유틸클래스를 스프링 빈으로 관리하겠다는 생각만 떠오르는데.. 이해할수있을만한 예시가있을까요..? 제가 못찾는건지 마땅히 그럴싸한 자료를 못봤던것같아서요 ㅠ
강의도중 @Component얘기가 잠깐나와서 생각이나서 질문드려봅니다...
답변 2
1
안녕하세요. 호돌맨입니다.
질문을 남겨주셔서 감사합니다.
코드에서 보여드린 부분은 꼭 @Component로 만들지 않아도 되서 뺐습니다. 저라면 추가할것 같습니다.
그래서 @Component와 별개로 static
vs 일반 클래스
정도로 생각해보면 좋을것 같습니다.
우선 저라면 테스트 코드를 위해서 그렇게 할 것 같습니다.
현재 회원가입시 요청보낸 비밀번호 1234
와 실제 DB에 들어가 있는 암호화비밀번호 값이 다르기 때문에 테스트 케이스 검증이 까다로웠습니다.
@Test
@DisplayName("회원가입 성공")
void test1() {
// given
Signup signup = Signup.builder()
.email("hodolman88@gmail.com")
.password("1234")
.name("호돌맨")
.build();
// when
authService.signup(signup);
// then
User user = userRepository.findAll().iterator().next();
assertNotNull(user.getPassword());
assertNotEquals("1234", user.getPassword());
}
현재는 user.getPassword()
가 null이 아니고 요청 보냈던 1234가 아닌지 만 검증한 찝찝한 상황이죠. 이를 정확하게 하려면 우리가 PasswordEncoder
를 통해 암호화 한 암호화비밀번호
가 맞는지를 확인해야합니다.
저는 아래와 같은 작업을 하겠습니다.
PasswordEncoder.java -> ScryptPasswordEncoder.java 파일명 변경, @Component 추가
PasswordEncoder.java interface 생성
public interface PasswordEncoder {
String encrypt(String rawPassword);
boolean matches(String rawPassword, String encryptedPassword);
}
ScryptPasswordEncoder.java에 PasswordEncoder interface 구현 (우리는 벌써 구현되어 있겠죠)
@Component
public class ScryptPasswordEncoder implements PasswordEncoder {
private static final SCryptPasswordEncoder encoder = new SCryptPasswordEncoder(
16,
8,
1,
32,
64);
@Override
public String encrypt(String rawPassword) {
return encoder.encode(rawPassword);
}
@Override
public boolean matches(String rawPassword, String encrpytedPassword) {
return encoder.matches(rawPassword, encrpytedPassword);
}
}
그러면 최종적으로 위와 같은 모습이 됩니다. (참고로 PasswordEncoder는 스프링에서도 제공하는 클래스이기 때문에 import에 유의 해야합니다.)
그러면 기존에 AuthService에서 만들었던 PasswordEncoder encoder = new PasswordEncoder()
를 아래와같이 주입받는 방식으로 변경할 수 있습니다.
@Service
@RequiredArgsConstructor
public class AuthService {
private final PasswordEncoder passwordEncoder;
public void signup(Signup signup) {
// ...
String encryptedPassword = passwordEncoder.encrypt(signup.getPassword());
var user = User.builder()
.password(encryptedPassword)
userRepository.save(user);
}
}
이렇게되면 우리는 테스트 시 PasswordEncoder를 Scrypt로 넘길지 혹은 다른거로 넘길지 결정 할 수 있게됩니다.
@SpringBootTest
class AuthServiceTest {
//@Autowired
//private AuthService authService;
@Test
@DisplayName("회원가입 성공")
void test1() {
// given
Signup signup = Signup.builder()
.email("hodolman88@gmail.com")
.password("1234")
.name("호돌맨")
.build();
AuthService authService = new AuthService(mockUserRepository, mockPasswordEncoder);
// when
authService.signup(signup);
}
현재는 테스트코드에서 AuthService를 @Autowired로 주입받고 있으나 위와 같이 mock객체를 넘겨 테스트 할 수도 있습니다. 다만 저희는 실제 애플리케이션 동작을 테스트 하고 있으므로 mock을 통해 AuthService를 만들어내는 것 보다 TestPasswordEncoder를 만들어내어 주입할 수 있겠죠.
우리는 @Profile별로 테스트가 가능하도록 만들 수 있습니다.
@TestComponent
public class TestPasswordEncoder implements PasswordEncoder {
@Override
public String encrypt(String rawPassword) {
return rawPassword;
}
@Override
public boolean matches(String rawPassword, String encrpytedPassword) {
return rawPassword.equals(encrpytedPassword);
}
}
위와 같이 Test를 위한 PasswordEncoder를 따로 만든 뒤 @TestComponent
를 추가합니다.
@Profile("default")
@Component
public class ScryptPasswordEncoder implements PasswordEncoder {
}
기존 ScryptPasswordEncoder를 위 처럼 @Profile("default")일때만 등록되게 어노테이션을 추가합니다.
@ActiveProfiles("test")
@SpringBootTest
@Import(TestPasswordEncoder.class)
class AuthServiceTest {
}
그리고 AuthServiceTest에 @ActiveProfile("test")를 추가하여 test profile로 실행되게 만들면 AuthService내에 PasswordEncoder가 주입될때 자동으로 @TestPasswordEncoder가 주입되게 만들 수 있습니다.
@Test
@DisplayName("회원가입 성공")
void test1() {
// given
Signup signup = Signup.builder()
.email("hodolman88@gmail.com")
.password("1234")
.name("호돌맨")
.build();
// when
authService.signup(signup);
// then
assertEquals(1, userRepository.count());
User user = userRepository.findAll().iterator().next();
assertEquals("1234", user.getPassword());
}
그러면 PasswordEncoder 인터페이스 구현체 (TestPasswordEncoder)를 통해서 비밀번호가 평문으로 잘 들어갔는지 확인할 수 있게됩니다.
이거 관련해서는 추가 영상을 만들도록 하겠습니다.
감사합니다.
0
아, 그리고 참고하시면 좋은 링크
백기선님의 스프링 제대로 공부했는지 5분안에 확인하는 방법 https://youtu.be/bJfbPWEMj_c
https://unluckyjung.github.io/spring/2022/05/02/spring-profile-annotation/
감사합니다.