calendar
Bcrypt 암호화적용
로드존슨
2023. 3. 17. 23:39
728x90
스프링 시큐리티로 패스워드 암호화가 있지만 가장 기본적인 Bcrypt 를 적용해보고 시큐리티 적용하는것도 같이 적어본다.
Bcrypt (따로 라이브러리 추가 없이 메소드로만 진행된다)
1)Encryptor 인터페이스를 만든다.
-수정과 관리가 용이하기 위해 인터페이스를 만들었고 encrypt , isMatch 메소드를 만든다.
2)BCryptEncryptor 클래스에서 Encryptor 를 구현한다.
3)UserService 클래스에 password 유효검증에 적용한다. Encryptor 를 통해 암호화모듈로 저장하고, 이를 해석한다.
그리고 UserService 에서 user를 저장하는 메소드에 암호화모듈을 적용하여 저장한다.
특이한점은 User 에 있는 isMatched 메소드이다. 스트래티지 패턴을 적용하여 유효검증을 하였느데
BCryptEncryptor 에 위임하여 유효성검증을 넘겼다.
(스트래티지 패턴 : 행위를 클래스로 캡슐화해 동적으로 행위를 자유롭게 바꿀수 있게 해주는 패턴)
->Encryptor 클래스로 캡슐화 하여 동적으로 해결한다. Encryptor 는 인터페이스라서 구현체가 BCryptEncryptor 되어있지만 암호화모듈 변경시 유지관리 및 확이 용이하여 이러한 패턴이 적용하였다.
한마디로, 로직을 구현하는 구현클래스 말고 인터페이스를 통해 알로리즘을 캡슐화한다.
public interface Encryptor {
//interface 를 자주 사용한다. 암호화모듈이 BCryptEncryptor 있을수도 있고
//여러가지모듈이 있는데, 필요할때 손쉽게 바꿀수 있게 interaface 적용
String encrypt(String origin);
//origin 문자를 받아서 암호화한 해쉬문자열을 반환하는 메소드
boolean isMatch(String origin, String hashed);
//해쉬된 문자와 ,origin 과 매치해서 맞는가 확인하는 메소드
}
public class BCryptEncryptor implements Encryptor {
@Override
public String encrypt(String origin) {
return BCrypt.hashpw(origin, BCrypt.gensalt());
}
@Override
public boolean isMatch(String origin, String hashed) {
try {
return BCrypt.checkpw(origin, hashed);
} catch (Exception e) { // 여러 예외가 있다.
return false;
}
}
}
@Service
@RequiredArgsConstructor
public class UserService {
private final Encryptor bcryptEncryptor;
private final UserRepository userRepository;
@Transactional
public User create(UserCreateReq req) {
userRepository.findByEmail(req.getEmail())
.ifPresent(u -> {
throw new RuntimeException("cannot find user");
});
return userRepository.save(User.builder()
.name(req.getName())
// .password(req.getPassword())
.password(bcryptEncryptor.encrypt(req.getPassword()))
.email(req.getEmail())
.birthday(req.getBirthday())
.build());
}
@Transactional
public Optional<User> findPwMatchUser(String email, String password) {
return userRepository.findByEmail(email)
.map(u -> u.isMatched(bcryptEncryptor, password) ? u : null);
}
}
@Table(name = "users")
public class User extends BaseEntity {
.
.
.
.
.
public boolean isMatched(Encryptor encryptor, String pw) {
return encryptor.isMatch(pw, this.password);
}
시큐리티 (아래문구를 그~대로 쓰고 메소드하나로 끝)
-로그인 양식을 통해 비밀번호가 제출되면 spring security의 필터 체인은 구성된 암호화 알고리즘을 비밀번호 값에 적용하여 암호화하여 서버로 전송합니다. 암
@Bean // 반드시 PasswordEncoder 등록을 해야 한다. 스프링 시큐리티에서 제공하는 암호화모듈을 활용할 수 있다.
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
//PasswordEncoderFactories 로부터 위임해서 passwordEncoder로 가지고 오겠다 라는 뜻
}
728x90