티스토리 뷰

개요

SpringBoot 2.7.5를 사용하다가 3.0.1로 올리면서 발생한 이슈들을 기록 해놓았습니다.

3.x에는 많은 것들이 바뀌었는데요 결국은 바뀐것을 써야하기 때문에 매도 먼저 맞자는 심정으로 이번에 새로 만드는 프로젝트에 적용 해보았습니다.

 

한국어로 된 문서가 별로 없는 것은 슬픈일이지만 저도 하나 만들고 다른 개발자님들께서도 하나씩 만들면되니까요.

 

순서

IntelliJ에서 Jdk 17설치

javax

Thymeleaf

SpringSecurity

jjwt 0.11.5의 .signWith()

Gradle SDK

기존 gradle 디렉토리 지우기

secretKey 길이 문제

Dockerfile

 

 

IntelliJ에서 Jdk 17설치

JDK를 따로 설치할것 없이 IntelliJ에서 클릭클릭으로 Jdk를 설치할 수 있습니다.

File --> Project Structure로 들어가서 아래와 같이 Add SDK --> Download JDK 를 눌러 설치 하시면 됩니다.

 

javax

Jdk17로 가면서 javax가 빠졌습니다.

그에 따른 문제들이 있습니다.

 

그래서 jakarta.persistence.* 로 바꾸어 주어야 하는데 이걸 바꾸면 기존에 2.7.x 에서 만든 Entity매핑들을 모두 다시 import해주어야 합니다. 주로 JPA관련 어노테이션들의 dependency가 많이 바뀌었습니다.

 

Entity들과 Service쪽을 돌면서 모두 바꿔주셔야 합니다.

 

 

Thymeleaf

thymeleaf에서 Spring Security를 쓰려면 springsecurity6를 써야 합니다.

// Thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'

 

thymeleaf-extras-springsecurity6는 나온지 얼마 안돼서 한국어로 된 문서가 별로 없네요.

https://github.com/thymeleaf/thymeleaf-extras-springsecurity

 

GitHub - thymeleaf/thymeleaf-extras-springsecurity: Thymeleaf "extras" integration module for Spring Security 3.x and 4.x

Thymeleaf "extras" integration module for Spring Security 3.x and 4.x - GitHub - thymeleaf/thymeleaf-extras-springsecurity: Thymeleaf "extras" integration module for Spring Secu...

github.com

위 링크를 참조하시면 됩니다. Role은 앞에 ROLE_ 을 붙여주어야 인식을 합니다. 그래서 저도 싹다 바꿨습니다.

 

SpringSecurity

Security쪽은 아래 포스트를 참고 해주세요.

https://krksap.tistory.com/2191

 

SpringBoot 3.x에서 Security변경사항

SpringBoot 2.x버전 --> SpringBoot 3.x버전 으로 올라옴에 따라 .authorizeRequests()가 depreciated되었습니다. SpringBoot 2.x버전 @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { return http

krksap.tistory.com

 

JWT발급

jjwt 0.11.5로 바뀌면서 .signWith이 depreciate되었습니다.

 

이전 버전

// JWT Token 발급
public static String createToken(String userName, String key, long expireTimeMs) {
    // Claim = 일종의 Map, userName을 넣어 줌으로써 나중에 userName을 꺼낼 수 있음
    Claims claims = Jwts.claims();
    claims.put("userName", userName);

    return Jwts.builder()
            .setClaims(claims)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + expireTimeMs))
            .signWith(SignatureAlgorithm.HS256, key)
            .compact();
}

기존에는 SignatureAlgorithm과 key를 넣었는데 이 메소드가 depreciated된 것입니다.

 

새 버전(0.11.5)

private static Key getSigningKey(String secretKey) {
    byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
    return Keys.hmacShaKeyFor(keyBytes);
}
// JWT Token 발급
public static String createToken(String userName, String key, long expireTimeMs) {
    // Claim = 일종의 Map, userName을 넣어 줌으로써 나중에 userName을 꺼낼 수 있음
    Claims claims = Jwts.claims();
    claims.put("userName", userName);

    return Jwts.builder()
            .setClaims(claims)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + expireTimeMs))
            .signWith(getSigningKey(key), SignatureAlgorithm.HS256)
            .compact();
}

key를 먼저 넣어야 합니다. key는 인코딩을 꼭 해서 넣어야 합니다. 두번째 파라메터로 알고리즘을 넘깁니다.

 

 

build.gradle

여기에서 크게 바뀐점은 org.springframework.boot가 3.0.1을 썼다는 것과 sourceCompatibility = '17'을 썼다는 것 그리고 jjwt를 0.11.5를 썼다는 것입니다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.0.1'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'org.hibernate.orm' version '6.1.6.Final'
    id 'org.graalvm.buildtools.native' version '0.9.18'
}

group = 'com.project'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-devtools'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'

    // Swagger 3.0.0 적용
    implementation 'io.springfox:springfox-swagger-ui:3.0.0'
    implementation 'io.springfox:springfox-boot-starter:3.0.0'


    // jjwt 0.9.1 -> 0.11.5로 버전업
    implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
    runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
    runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

    // Thymeleaf
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'

    // Validation
    implementation 'org.springframework.boot:spring-boot-starter-validation'

    testImplementation 'com.h2database:h2'
}

tasks.named('test') {
    useJUnitPlatform()
}

 

Gradle의 JDK

실행 하면 아래와 같이 Gradle 관련 에러가 납니다.

Settings -> Gradle

 

Gradle JVM버전도 올려 주어야 합니다.

 

기존 gradle 디렉토리 지우기

gradle디렉토리를 지우지 않으면 계속 이전 버전의 gradle wrapper를 씁니다.

 

 

 

디렉토리를 지우고 다시 실행을 하면 새로운 버전으로 gradle디렉토리가 생성 됩니다.

 

gradle디렉토리의 파일을 git에 올렸다면 이 파일들도 commit해주셔야 합니다.

 

 

 

실행할 때 문제

오류: 기본 클래스 com.project.feedback.FeedbackApplication을(를) 로드하는 중 LinkageError가 발생했습니다.
java.lang.UnsupportedClassVersionError: com/project/feedback/FeedbackApplication has been compiled
by a more recent version of the Java Runtime (class file version 61.0), this version of the
Java Runtime only recognizes class file versions up to 55.0

 

 

 

Java 17이하 버전으로 실행하고 있으면 위 에러가 납니다.

 

File -> Project Structure...로 갑니다.

SDK를 Java 17로 바꿔줍니다.

 

 

Secret Key의 길이 문제

io.jsonwebtoken.security.WeakKeyException: The signing key's size is 72 bits which 
is not secure enough for the HS256 algorithm.  The JWT JWA Specification (RFC 7518, Section 3.2)
states that keys used with HS256 MUST have a size >= 256 bits (the key size must be greater than
or equal to the hash output size).  Consider using the io.jsonwebtoken.security.Keys class's
'secretKeyFor(SignatureAlgorithm.HS256)' method to create a key guaranteed to be secure enough for 
HS256.  See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.

 

 

secret이 짧아서 발생하는 문제 입니다.

# Jwt Secret Key
jwt:
  token:
    secret: ssssss000000

이전에 쓰던 secret의 자릿수 입니다. 짧긴 했습니다. 길게 늘려줍니다.

 

Dockerfile

기존에 docker로 빌드하고 있었다면 빌드가 안될 수 있습니다.

FROM gradle:7.5.1-jdk17-alpine as builder
FROM openjdk:17.0-slim

 

From 이미지를 jdk17로 올려줍니다.

 

 

 

마이그레이션 완료.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함