관리 메뉴

bright jazz music

blog41 : 회원가입과 비밀번호 암호화-4 본문

Projects/blog

blog41 : 회원가입과 비밀번호 암호화-4

bright jazz music 2023. 2. 26. 20:17

 

- 테스트 케이스 개선

 

로컬에서 테스트 할 때는 굳이 암호화하여 테스트 할 필요 없으므로 평문을 사용하는 PasswordEncoder를 하나 더 생성하여 테스트 해볼 수 있다. 따라서 로컬에서 테스트 할 때는 평문을 사용하는 encoder를 주입하고, 운영에서는 암호화를 사용하는 encoder를 사용하는 것이다. 그렇게 하면 asserEquals()를 사용하여 테스트 할 수 있다.

 

 

1.PasswordEncoder 인터페이스 생성

//PasswordEncoder.java

package com.endofma.blog.crypto;

public interface PasswordEncoder {

    String encrypt(String rawPassword);

    boolean matches(String rawPassword, String encryptedPassword);
}

- 기존의 PasswordEncoder클래스의 이름을 ScryptPasswordEncoder로 변경하고 이 인터페이스를 구현하도록 만든다.

- PlainPasswordEncoder를 생성하여 이 인터페이스를 구현하도록 만든다.

- 스프링 자체에서 제공하는 PasswordEncoder가 존재하므로 잘못 구현하지 않도록 주의

 

1. PasswordEncoder를 ScryptPasswordEncoder로 이름 변경하고 PasswordEncoder 인터페이스 구현 (운영 시 사용할 클래스)

//PasswordEncoder.java

package com.endofma.blog.crypto;

import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import org.springframework.stereotype.Component;

@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 encryptedPassword) {
        return encoder.matches(rawPassword, encryptedPassword);
    }

}

 

2. PlainPasswordEncoder 생성( 로컬 테스트용)

//PlainPasswordEncoder.java

package com.endofma.blog.crypto;

import org.springframework.stereotype.Component;

@Component
public class PlainPasswordEncoder implements PasswordEncoder{
    @Override
    public String encrypt(String rawPassword) {
        return rawPassword;
    }

    @Override
    public boolean matches(String rawPassword, String encryptedPassword) {
        return rawPassword.equals(encryptedPassword);
    }
}

 

 

4. 테스트 시 PlainPasswordEncoder 로 주입하도록 설정하기

 

4.1 AuthServiceTest.java에 @ActiveProfiles() 설정

//AuthServiceTest.java

package com.endofma.blog.service;

import com.endofma.blog.crypto.PasswordEncoder;
import com.endofma.blog.crypto.PlainPasswordEncoder;
import com.endofma.blog.domain.User;
import com.endofma.blog.exception.AlreadyExistsEmailException;
import com.endofma.blog.exception.InvalidSigninInformation;
import com.endofma.blog.repository.UserRepository;
import com.endofma.blog.request.Login;
import com.endofma.blog.request.Signup;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.function.Executable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

import static org.junit.jupiter.api.Assertions.*;

@ActiveProfiles("test") //실행 시 test라는 profile로 실행할 것
@SpringBootTest
class AuthServiceTest {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private AuthService authService;

    @AfterEach
    void clean() { userRepository.deleteAll();}

    //AuthServiceTest.java
    @Test
    @DisplayName("회원가입")
    void test1(){
        //given
        Signup signup = Signup.builder()
                .email("catnails@gmail.com")
                .password("1234")
                .name("catnails")
                .build();

        //when
        authService.signup(signup);

        //then
        Assertions.assertEquals(1, userRepository.count());

        User user = userRepository.findAll().iterator().next();
        Assertions.assertEquals("catnails@gmail.com", user.getEmail());
        Assertions.assertNotNull(user.getPassword());
//        Assertions.assertNotEquals("1234", user.getPassword());
        Assertions.assertEquals("1234", user.getPassword());
        Assertions.assertEquals("catnails", user.getName());
    }

    //AuthServiceTest.java
    @Test
    @DisplayName("회원가입 시 중복된 이메일")
    void test2(){
        //given
        User user = User.builder()
                .name("catnails")
                .email("catnails@gmail.com")
                .password("1234")
                .build();
        userRepository.save(user);

        Signup signup = Signup.builder()
                .email("catnails@gmail.com")
                .password("1234")
                .name("catnails")
                .build();

        //expected
        Assertions.assertThrows(AlreadyExistsEmailException.class, () -> authService.signup(signup));

    }

    //AuthServiceTest.java
    @Test
    @DisplayName("로그인 성공")
    void test3(){
        //given
//        PasswordEncoder encoder = new PasswordEncoder();  평문으로 테스트 하기로 했으므로 주석처리
        PlainPasswordEncoder encoder = new PlainPasswordEncoder();
        String encryptedPassword = encoder.encrypt("1234");

        User user = User.builder()
                .email("catnails@gmail.com")
                .password(encryptedPassword)
                .name("catnails")
                .build();

        userRepository.save(user);
//        authService.signup(signup);

        Login login = Login.builder()
                .email("catnails@gmail.com")
                .password("1234")
                .build();

        //when
        Long userId = authService.signin(login);

        //then
        Assertions.assertNotNull(userId);
    }

    //AuthServiceTest.java
    @Test
    @DisplayName("로그인 시 비밀번호 틀림")
    void test4(){
        //given
//        PasswordEncoder encoder = new PasswordEncoder(); 평문으로 테스트 하기로 했으므로 주석처리
        PlainPasswordEncoder encoder = new PlainPasswordEncoder();
        String encryptedPassword = encoder.encrypt("1234");

        User user = User.builder()
                .email("catnails@gmail.com")
                .password(encryptedPassword)
                .name("catnails")
                .build();

        userRepository.save(user);

        Login login = Login.builder()
                .email("catnails@gmail.com")
                .password("5678") //비밀번호 틀림
                .build();

        //expected
        Assertions.assertThrows(InvalidSigninInformation.class,
                () -> authService.signin(login));
    }
}

@ActiveProfiles("test")를 사용하여 test라는 profile을 사용할 것을 명시하였다.

 

 

4.2 PlainPasswordEncoder에 @Profile() 어노테이션 설정

//PlainPasswordEncoder.java

package com.endofma.blog.crypto;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Profile("test") //prifile이 "test"일 경우에만 bean으로 생성
@Component
public class PlainPasswordEncoder implements PasswordEncoder{
    @Override
    public String encrypt(String rawPassword) {
        return rawPassword;
    }

    @Override
    public boolean matches(String rawPassword, String encryptedPassword) {
        return rawPassword.equals(encryptedPassword);
    }
}

@Profile("test")를 명시하여 PlainPasswordEncoder가 test임을 명시하였다.

 

4.3 ScryptPasswordEncoder에 @Profile() 어노테이션 설정

반드시 @Profile("test")가 아님을 명시해 줄 것. default를 사용

//PasswordEncoder.java

package com.endofma.blog.crypto;

import org.springframework.context.annotation.Profile;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import org.springframework.stereotype.Component;

@Profile("default") //반드시 설정해 줘야한다. 설정이 test라도 여기에 test가 아님을 명시하지 않으면 bean으로생 성된다.
@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 encryptedPassword) {
        return encoder.matches(rawPassword, encryptedPassword);
    }

}

 

5. 테스트

성공

 

Comments