관리 메뉴

bright jazz music

blog39 : 회원가입과 비밀번호 암호화-2 본문

Projects/blog

blog39 : 회원가입과 비밀번호 암호화-2

bright jazz music 2023. 2. 26. 15:32

비밀번호 저장을 위해 Scrypto 알고리즘을 사용한다.

Scrypto를 지원하는 다양한 라이브러리들이 존재한다.

이 프로젝트에서는 Spring security에서 지원하는 Crypto 라이브러리를 사용한다.

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/scrypt/package-summary.htm

 

org.springframework.security.crypto.scrypt (spring-security-docs 6.0.2 API)

package org.springframework.security.crypto.scrypt Classes

docs.spring.io

https://mvnrepository.com/artifact/org.springframework.security/spring-security-crypto

// https://mvnrepository.com/artifact/org.springframework.security/spring-security-crypto
implementation group: 'org.springframework.security', name: 'spring-security-crypto', version: '6.0.1'

 

1. build.gradle에 암호화 라이브러리 추가

 

2. AuthService.java에 비밀번호 암호화 로직 추가

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/scrypt/SCryptPasswordEncoder.html

 

SCryptPasswordEncoder (spring-security-docs 6.0.2 API)

Constructs a SCrypt password encoder with cpu cost of 65,536, memory cost of 8, parallelization of 1, a key length of 32 and a salt length of 16 bytes.

docs.spring.io

 

  //AuthService.java
    //회원가입
    public void signup(Signup signup) {

        //email 중복체크
        Optional<User> userOptional = userRepository.findByEmail(signup.getEmail());
        if(userOptional.isPresent()) {
            throw new AlreadyExistsEmailException();
        }

        //비밀번호 암호화 (cpuCost, memoryCost, parallelization, keyLength, saltLength)
        //보통 salt는 uuid를 생성하여 65바이트로 넣어준다. 이 라이브러리는 내부적으로 하는 모양
        SCryptPasswordEncoder encoder = new SCryptPasswordEncoder(16, 8, 1, 32, 64);
        String encryptedPassword = encoder.encode(signup.getPassword());


        //엔티티로 변환
        var user = User.builder()
                .name(signup.getName())
                .password(encryptedPassword)
                .email(signup.getEmail())
                .build();

        userRepository.save(user);
    }
}

 

3. 회원가입 테스트

//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.assertEquals("1234", user.getPassword());
    Assertions.assertEquals("catnails", user.getName());
}

문제 발생

org/bouncycastle/crypto/generators/SCrypt
java.lang.NoClassDefFoundError: org/bouncycastle/crypto/generators/SCrypt
at org.springframework.security.crypto.scrypt.SCryptPasswordEncoder.digest(SCryptPasswordEncoder.java:166)
at org.springframework.security.crypto.scrypt.SCryptPasswordEncoder.encode(SCryptPasswordEncoder.java:121)

SCryptPasswordEncoder 클래스 내부에서 사용하는 라이브러리가 존재하지 않아서 생기는 문제.

 

아래 라이브러리를 build.gradle에 추가하여 해결

https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on/1.70

build.gradle 디펜던시에 추가

 

재테스트

 

암호화 된 비밀번호가 입력됐으므로 당연히 실패

 

4. 테스트 통과시키기

암호화는 랜덤으로 진행되므로 우리가 결괏값을 예측할 수 없다. 따라서 다음과 같이 암호가 null이 아니며, "1234"와 같지 않다는 것으로 설정하여 성공시킨다.

 

    //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());
    }

성공

Comments