안녕하세요 유틸클래스 질문있습니다
1193
작성자 없음
작성한 질문수 0
보통 암호화하는 클래스들을 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/
감사합니다.
Deprecated 관련 사항들
0
105
2
깃헙 collaboator 초대 관련
0
89
1
강의 듣다가 도커 이미지 생성시 각각도 가능하나 그렇게 사용하는데가 많은지 모르겠다라는 말을 듣고 남김니다
0
157
2
logout 후에 login 페이지 이동은 어디서 시켜주는건가요?
0
233
1
다중 데이터를 삭제 할 때
0
271
2
querydsl Q class 이슈
0
417
2
Windows WSL Vue 설정
2
247
1
Dip, @transactional
0
189
1
[vite] http proxy error: /auth/login
0
1047
2
로그인 하고 나서 GET요청으로 메인페이지 요청
0
234
2
GitHub Collaborator 초대 관련
0
258
2
Window에서 Vue.js 설정
0
322
2
collaboator로 초대받을 수 있을까요??
0
283
2
SecurityMockContext 로부터 유저 정보를 가져오기
0
262
1
섹션9 프론트의 코드를 보고싶습니다,,,
0
423
1
Spring Security - defaultSuccessUrl 질문
0
627
1
강의 화면이 나오지 않습니다. 음성과 자막만 나와요
0
303
1
JPAQueryFactory(em)의 객체 생성자 오류에 대해서 질문이 있습니다ㅜㅜ
0
690
2
ExceptionHandler가 AccessDeniedHandler(Http403Handler)를 먹어버리는 현상
0
1182
2
섹션10 언제 나오나요?
0
485
1
CommentService에서 Repository를 호출하지 않는데도
0
345
1
Editor....를 활용한 패턴에 질문있습니다.
0
496
1
섹션9 vue
0
456
2
Post에 edit 메서드 삼항연산자 질문
0
476
2





