PasswordEncoder
사용자 세부정보를 찾은 후에 요청에서 얻은 자격증명과 사용자 세부정보에 자격증명과 비교를 한다.
정의
encode()는 주어진 자격증명을 해시나 암호화를 한다.
amtches()는 주어진 자격증명과 암호화나 해시화된 자격증명과 일치하는 지 확인한다.
upgrageEncoding() 경우 인코딩된 비밀번호를 다시 인코딩해야 하는 경우 true를 반환하도록 재정의한다.
단순한 구현
암호기능 없음
public class PlainTextPasswordEncoder implements PasswordEncoder{
public String encode(CharSequence rawPassword) {
return rawPassword.toString();
}
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return Objects.equals(rawPassword, encodedPassword);
}
}
테스트
class SpringSecurity04PasswordApplicationTests {
@Test
void 단순_암호_인코더_테스트() {
PlainTextPasswordEncoder encoder = new PlainTextPasswordEncoder();
String password = "tiger";
assertThat(encoder.matches(password,encoder.encode(password))).isTrue();
}
}
학습 테스트를 위한 구현이지, 실제로는 이미 구현된 클래스를 가져다 쓴다.
암호화 알고리즘 기능은 개발자가 구현할 일도 없다.
나머지 테스트
SCryptPasswordEncoder는 추가로 의존하는 라이브러리가 있다.
DelegatingPasswordEncoder
자격증명을 검증할 때 다양한 알고리즘이 필요한 경우 사용한다.
자격증명 앞에 접두로 "{알고리즘}" 을 붙여 각 상황에 맞게 알고리즘을 실행한다.
예시
{noop}tiger , 인코딩하지 않는다.
{bcrypt}tiger , BCryptPasswordEncoder로 인코딩한다.
BCryptPasswordEncoder는 기능 구현을 하지 않고, 모든 책임을 구성 PasswordEncoder 에게 위임한다.
사용해보기
직접 생성하지 않고, 스프링 시큐리티가 제공하는 팩터리에서 생성해서 사용할 수 있다.
CustomPassword 추가
만일 커스텀한 PasswordEncoder가 있다면, 직접 생성해야 한다.
createDelegatingPasswordEncoder() 메서드를 그대로 복사해, 커스텀 구현체를 넣어 사용하면 된다.
암호화 키 생성
암호화 및 복호화 함수와 키 생성 기능은 자바 언어에서 기본 제공되지 않는다.
스프링 시큐리티는 이를 위해 자체 솔루션을 제공한다.
키 생성기
문자열 기반, 바이트 기반 두 가지 인터페이스가 존재한다.
암/복호화
사용해보기
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;
import org.springframework.security.crypto.encrypt.BytesEncryptor;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;
import org.springframework.security.crypto.keygen.KeyGenerators;
import org.springframework.security.crypto.keygen.StringKeyGenerator;
public class Test2 {
public static void main(String[] args) {
stringBasedEncrption();
System.out.println();
byteBasedEncrption();
}
private static void stringBasedEncrption() {
System.out.println("문자열 기반 암호화");
StringKeyGenerator keyGenerator = KeyGenerators.string();
String password = "tiger";
String solt = keyGenerator.generateKey();
//암호화 하지 않음
// TextEncryptor encryptor = Encryptors.noOpText();
//기본
// TextEncryptor encryptor = Encryptors.text(password, solt);
//더 강력
TextEncryptor encryptor = Encryptors.delux(password, solt);
String plainText = "민감한 데이터";
//encrypt() 매 실행 마다 값이 다르다. 내부적으로 난수를 사용한다.
String cypherText1 = encryptor.encrypt(plainText);
String cypherText2 = encryptor.encrypt(plainText);
System.out.println("plainText = " + plainText);
System.out.println("cypherText1 = " + cypherText1);
System.out.println("cypherText2 = " + cypherText2);
System.out.println(encryptor.decrypt(cypherText1));
System.out.println(Objects.equals(plainText, encryptor.decrypt(cypherText1)));
}
private static void byteBasedEncrption() {
System.out.println("바이트 기반 암호화");
StringKeyGenerator keyGenerator = KeyGenerators.string();
String password = "민감한 데이터";
String solt = keyGenerator.generateKey();
//기본
// BytesEncryptor encryptor = Encryptors.standard(password, solt);
//더 강력
BytesEncryptor encryptor = Encryptors.stronger(password, solt);
byte[] plainByte = password.getBytes(StandardCharsets.UTF_8);
//encrypt() 매 실행 마다 값이 다르다. 내부적으로 난수를 사용한다.
byte[] cypherByte1 = encryptor.encrypt(plainByte);
byte[] cypherByte2 = encryptor.encrypt(plainByte);
System.out.println("plainByte" + Arrays.toString(plainByte));
System.out.println("cypherByte1 = " + Arrays.toString(cypherByte1));
System.out.println("cypherByte2 = " + Arrays.toString(cypherByte2));
System.out.println(new String(encryptor.decrypt(cypherByte1), StandardCharsets.UTF_8));
System.out.println(Objects.equals(plainByte, encryptor.decrypt(cypherByte1)));
}
}
'개발 > 스프링 시큐리티' 카테고리의 다른 글
스프링 시큐리티 인 액션 - 인증 구현 (0) | 2023.09.04 |
---|---|
스프링 시큐리티 인 액션 - 사용자 관리 (0) | 2023.08.30 |
스프링 시큐리티 인 액션 - 안녕! 스프링 시큐리티 (0) | 2023.08.23 |
스프링 시큐리티 인증 아키텍처 (0) | 2023.08.17 |
스프링 시큐리티 인 액션 - 오늘날의 보안 (0) | 2023.08.15 |