개발 무지렁이

[Spring Boot] 인코딩 및 암호화 알고리즘을 통해 비밀키 생성, 이를 사용해 Jwt의 헤더와 페이로드를 서명 (무결성 보장) 본문

Backend/스프링부트

[Spring Boot] 인코딩 및 암호화 알고리즘을 통해 비밀키 생성, 이를 사용해 Jwt의 헤더와 페이로드를 서명 (무결성 보장)

Gaejirang-e 2023. 9. 27. 16:13

𐂂 JwtConfig

📜 jwt 비밀키 생성 객체 Bean등록.java

  @Configuration
  public class JwtConfig {
      @Value("${custom.jwt.secretKey}")
      private String secretKeyPlain;

      @Bean
      public SecretKey jwtSecretKey() {
          String keyBase64Encoded = Base64.getEncoder().encodeToString(secretKeyPlain.getBytes());
          return Keys.hmacShaKeyFor(keyBase64Encoded.getBytes());
      }
  }
🦉 @Value("${ }")
: 외부 설정파일에서(properties, yml..)에서 값을 가져와 해당 클래스의 필드주입하는데 사용된다.

🦉 Base64 (3Bytes[24bits] 이진데이터 -> 4개 Base64 문자[24bits / 1문자, 6bits]로 변환)
[ 알파벳 대/소문자, 숫자, +, / ]
: 이진데이터텍스트 형식으로 인코딩하거나, 반대로 디코딩하는데 사용되는 인코딩 체계 중 하나이다.

🍟 이메일 첨부파일 (텍스트 형식의 데이터만 지원)
🍟 웹 이미지 (이미지 파일을 데이터 url인코딩하여 웹페이지에 표시)
🍟 암호화 (일부 암호화 알고리즘에서 Base64 인코딩을 사용해, 암호화된 데이터텍스트로 표현)

🐘 implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
🐘 runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
🐘 runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

🦉 Keys 클래스
: JWT서명(Signature, 비밀키) 생성검증을 위한 키(Material, 공개키)관리하는 데 사용된다.
⚠️ 서명(Signature)을 생성함으로써 JWT🧩 무결성을 보장, 위조 방지한다.

🗝️ Keys.hmacShaKeyFor(keyBasedEncoded.getBytes());
HMAC-SHA(Hash-based Message Authentication Code - Secure Hash Algorithm)라는 알고리즘기반
JWT 서명(비밀키, SecretKey)생성

❓javax.crypto.SecretKey
: Java에서 비밀키나타내기 위해 사용되는 인터페이스

𐁍 JwtProvider

📜 Jwt의 관련정보를 다루는 JwtProvider.java

  @Component
  @RequiredArgsConstructor
  public class JwtProvider {
      private final SecretKey jwtSecretKey

      private SecretKey getSecretKey() {
          return jwtSecretKey;
      }

      public String generateAccessToken(Map<String, Object> claims, int seconds) {
          long now = new Date().getTime();
          Date accessTokenExpiresIn = new Date(now + 1000L * seconds);

          return Jwts.builder()
              .claim("body", Util.json.toStr(claims))
              .setExpiration(accessTokenExpiresIn) //유효기간 설정
              .signWith(getSecretKey(), SignatureAlgorithm.HS512) //서명
              .compact();
      }
  }

📜 Util.java

  public class Util {
      private static ObjectMapper getObjectMapper() {
          return (ObjectMapper) AppConfig.getContext().getBean("objectMapper");
      }

      public static class json {
          public static Object toStr(Map<String, Object> map) {
              try {
                  return getObjectMapper().writeValueAsString(map);
              } catch(JsonProcessingException e) {
                  return null;
              }
          }

          public static Map<String, Object> toMap(String jsonStr) {
              try {
                  return getObjectMapper().realValue(jsonStr, LinkedHashMap.class);
              } catch(JsonProcessingException e) {
                  return null;
              }
          }
      }
  }

📜 AppApplication.java

  @SpringBootApplication
  public class AppApplication {
      public static void main(String[] args) {
          SpringApplication.run(AppApplication.class, args);
      }

      @Bean
      public ObjectMapper objectMapper() {
          return new ObjectMapper();
      }
  }

📜 AppConfig.java

  @Configuration
  public class AppConfig {
      @Getter
      private static ApplicationContext context;

      @Autowired
      public void setContext(ApplicationContext context) {
          AppConfig.context = context;
      }
  }
🦉 클레임(claim)
: Jwt정보를 표현하는데 사용하는 용어를 말한다.

🦉 왜 getObjectMapper()를 통해서 ObjectMapper객체를 가져올까?
* 그냥 private ObjectMapper objectMapper 필드에 @Autowired를 붙여서 사용하면 되는거 아닌가? *
위의 코드를 보면 objectMapper를 사용하는 곳은 static 메서드 안이다.
static 메서드에서 사용되려면 static 필드여야하는데, static을 붙이면 @Autowired를 사용할 수 없다. *
따라서 위의 코드와 같이 ApplicationContext를 가져와 등록된 Bean
'objectMapper'라는 이름의 Bean을 가져온다.

이렇게 Bean을 가져올 수 있는 것은
진입점클래스(entry point class)에서 ObjectMapper 객체Bean으로 등록했기 때문이다.
(@SpringBootApplication 안에 @Configuration이 있어 해당 클래스를 살펴 @Bean이 있으면 Bean으로 등록한다.)

❓ objectMapper
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.14.2'
- JSON 직렬화 (Collections ➡️ JSON)
- JSON 역직렬화 (JSON ➡️ Collections)

ApplicationContext: 스프링 애플리케이션의 설정정보를 읽고 객체를 관리하는 역할을 한다.

📕 참고 자료 📕
Tistory's Card

Comments