JWT 예제 구현 (12) 3.0.1 버전 업그레이드
3.01로 업데이트 하기 위한 작업
*** 자바 버전을 반드시 17 이상으로 해야 한다!
build.gradle
plugins {
id 'java'
// 두 개 수정
id 'org.springframework.boot' version '3.0.1'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'inflearn'
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-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
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'
}
tasks.named('test') {
useJUnitPlatform()
}
gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
# 버전 업그레이드
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
SecurityConfig
package inflearn.freejwt.config;
import inflearn.freejwt.jwt.JwtAccessDeniedHandler;
import inflearn.freejwt.jwt.JwtAuthenticationEntryPoint;
import inflearn.freejwt.jwt.JwtSecurityConfig;
import inflearn.freejwt.jwt.TokenProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;
@EnableWebSecurity // 기본적인 웹 시큐리티 설정을 활성화하겠다.
@EnableMethodSecurity // 추가
@Configuration
@RequiredArgsConstructor
public class SecurityConfig { // extend 삭제
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// WebSecurityCustomizer 삭제
/**
*
* @param http the {@link HttpSecurity} to modify
* @throws Exception
*
* 많은 부분들을 추가
* : 토큰을 사용하기 때문에 csrf 설정은 disable
* Exception을 핸들링할 때 만들었던 클래스들을 추가한다.
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
// token을 사용하는 방식이기 때문에 csrf를 disable한다.
httpSecurity.csrf().disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler)
// h2-console을 위한 설정
.and()
.headers()
.frameOptions()
.sameOrigin()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // session을 사용하지 않음.
.and()
// 이부분 전부 수정
.authorizeHttpRequests()
.requestMatchers("/api/hello", "/api/authenticate", "/api/signup").permitAll()
.requestMatchers(PathRequest.toH2Console()).permitAll()
.anyRequest().authenticated()
.and()
.apply(new JwtSecurityConfig(tokenProvider));
return httpSecurity.build();
}
}
addAllowedOriginPattern 적용
CorsConfig
package inflearn.freejwt.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
// CORS 필터 빈을 정의하는 메서드
@Bean
public CorsFilter corsFilter() {
// URL 기반의 CORS 구성을 관리하는 객체 생성
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// CORS 구성 설정 객체 생성
CorsConfiguration config = new CorsConfiguration();
// 요청에서 자격 증명(자격 증명 쿠키, 인증 등)을 허용
config.setAllowCredentials(true);
// // 모든 출처(Origin)를 허용
// config.addAllowedOrigin("*");
config.addAllowedOriginPattern("*");
// 모든 HTTP 헤더를 허용
config.addAllowedHeader("*");
// 모든 HTTP 메서드(GET, POST, PUT, DELETE 등)를 허용
config.addAllowedMethod("*");
// "/api/**" 패턴에 해당하는 엔드포인트에 대해 CORS 구성을 등록
source.registerCorsConfiguration("/api/**", config);
// CORS 필터를 생성하고 반환
return new CorsFilter(source);
}
}
addAllowedOrigin("*")와 config.addAllowedOriginPattern("*")
config.addAllowedOrigin("*")와 config.addAllowedOriginPattern("*")는
CORS (Cross-Origin Resource Sharing) 설정에서 다르게 작동하는 두 가지 방법을 나타낸다.
1. config.addAllowedOrigin("*"):
이 설정은 모든 출처(Origin)를 허용하는 것을 의미한다.
즉, 어떤 도메인이든 자원에 접근할 수 있도록 CORS 정책을 완전히 비활성화한다.
이 설정은 보안에 취약할 수 있으므로 주의해서 사용해야 합니다. 개발 또는 테스트 목적으로만 사용해야 된다.
2. config.addAllowedOriginPattern("*"):
이 설정은 출처 패턴을 허용하는 것을 의미한다.
출처 패턴은 정규 표현식과 유사한 방식으로 동작하며, 특정 출처 패턴과 일치하는 도메인만 허용된다.
예를 들어, "https://example.com"과 같은 특정 출처를 허용하거나,
"https://*.example.com"과 같은 와일드카드 패턴을 사용하여 특정 도메인과 하위 도메인을 허용할 수 있다.
이 방법은 더 세밀한 제어를 제공하며, 보안을 더 강화할 수 있다.
일반적으로 보안을 고려하고 정확한 출처를 허용하려면
config.addAllowedOriginPattern("*") 대신 실제 도메인 또는 도메인 패턴을 지정하여 사용하는 것이 좋다.
config.addAllowedOrigin("*")은 개발 중에 테스트를 위해 사용되거나 보안이 필요하지 않은 상황에서만 사용해야 한다.