이전 IoC와 DI에 대한 내용 복습겸 정리부터 시작
@Component를 사용하면 @ComponentScan에 의해 자동으로 스캔되어 해당 클래스를 Bean으로 등록 해준다.
이미 이전의 @Controller @RestController @Service @Repository 등 은 @Component 라는 어노테이션을 포함하고 있으며, @ComponentScan 에 의해서 @SpringBootApplication 이 등록된 어플리케이션의 진입부 메인 클래스의 경로 및 하위 경로를 스캔하면서 @Component 가 등록된 클래스들을 IoC Container에 해당 컴포넌트들을 찾아낸다.
결과적으로 Bean으로 등록되면서 DI(의존성 주입)이 진행된다. 이는 곧 해당 SpringBoot 어플리케이션 내에서는 등록되어있는 Bean들의 멤버를 자유롭게 접근 할 수 있는 개념이다.
이렇게 어노테이션을 통한 Bean등록은 이미 Spring 내에서 ‘자동 등록’ 시스템이 갖춰진 상황으로 볼 수 있다. 또한 이러한 환경을 제공하는 Spring Framework내에서는 일반적으로 @Component를 사용하여 Bean을 자동으로 등록하는 것이 좋은것으로 권장되고 있다.
수동 등록이 필요한 경우?
기술적인 문제나 공통적인 관심사를 처리 할 때 사용되는 객체들은 수동으로 등록하는 것이 좋다. 비지니스 로직 Bean보다는 그 수가 적기 때문에 수동 등록해서 살펴볼만하다. 수동등록된 Bean에서 문제가 발생했을 때 해당 위치를 파악하기 쉽다는 장점이 있다.
비밀번호 암호화 메소드를 수동 등록해보자
Bean을 수동으로 등록하는 실습을 하고자 어짜피 추가해볼 기능인 비밀번호 암호화를 대상으로 진행해 보았다.
우선 수동 등록의 순서는 다음과 같다.
1.
Bean으로 등록하고자하는 객체를 반환하는 메서드를 선언하고 메소드에 @Bean을 설정
2.
Bean을 등록하는 메서드가 속한 해당 클래스에 @Configuration을 설정
3.
Spring 서버가 메모리에 오를 때 Spring IoC 컨테이너에 'Bean'으로 저장 됨
package com.sparta.springauth.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration //<-- 스프링서버가 IoC Container에 등록 해줌
public class PasswordConfig { //passwordConfig
@Bean
public PasswordEncoder passwordEncoder() { //<- 인터페이스라 구현체 넣어줘야함
return new BCryptPasswordEncoder(); //<- 인터페이스의 구현체는 BCryptPasswordEncoder()라는 메소드를 사용하는 것으로 추상클래스의 추상메소드를 구체화했다.
// Bcrypt란 비밀번호 암호화해주는 해시함수
}
}
Java
복사
비밀번호 암호화 메소드를 테스트해보자
테스트를 통해서 실제로 위 클래스와 메소드가 Bean으로 등록되었는지 확인 할 수 있다.
확인하는 코드는 다음과 같다.
package com.sparta.springauth;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
@SpringBootTest
public class PasswordEncoderTest {
@Autowired
PasswordEncoder passwordEncoder; //Bean으로 등록된것을 주입
@Test
@DisplayName("수동 등록한 passwordEncoder를 주입 받아와 문자열 암호화")
void test1() {
String password = "Robbie's password"; //현재 패스워드
// 암호화 encode()메소드에 paswword를 넣어봄
String encodePassword = passwordEncoder.encode(password);
System.out.println("encodePassword = " + encodePassword); //암호화 encode()실행 이후 password는 어떻게 변화했는지 확인
String inputPassword = "Robbie"; //이런 원본값을 '평문'이라고 부름
// 복호화를 통해 암호화된 비밀번호와 비교
boolean matches = passwordEncoder.matches(inputPassword, encodePassword); // matches(평문, 암호화된암호)로 평문과 암호화작업이후 비밀번호와 같은지 비교해줌, true or false를 반환
System.out.println("matches = " + matches); // 암호화할 때 사용된 값과 다른 문자열과 비교했기 때문에 false
}
}
Java
복사
실행 결과 Robbie’s password라는 원본 평문 비밀번호가
PasswordEncoder 라는 인터페이스 구현체 BCryptPasswordEncoder객체가 생성되었는데 @Bean 을 통해 IoC Container에 등록되어 Bean으로 등록되었다. 따라서 Test 메인 클래스인
PasswordEncoderTest 에서 @Autowired PasswordEncoder passwordEncoder;
로 정상적으로 객체를 사용 할 수 있는 것이다. 여기까지가 Bean으로 등록 되었다는 증거이다.
더하여 BCryptPasswordEncoder 의 메소드들 살펴보기
•
encode(password) 메소드 : 평문 비밀번호를 해싱 알고리즘을 적용한 암호화 과정을 거쳐 단방향(디코딩 불가) 암호화가 진행되게 된다.
•
matches(inputPassword, encodePassword) 메소드 : 두개의 값(입력된 평문 vs 암호화된 비밀번호)을 비교하여 일치하는지 true or false를 반환하는 메소드이다. 해독이 불가능한 단방향 암호화기 때문에 실제로는 로그인 같은 상황에서 클라이언트에서 입력한 값을 암호화하고 VS DB의 회원 정보 중 암호화된 비밀번호를 비교하여 비밀번호 일치 여부를 따질 때 사용하는 사례가 예상된다.