Skip to content

Commit

Permalink
Merge pull request #8 from Starlight258/feat/dockerizing
Browse files Browse the repository at this point in the history
[Feat/#1,5,6] 도커 환경 지원 및 H2 DB 파일 기반으로 전환
  • Loading branch information
FacerAin authored Jan 30, 2024
2 parents e31fd35 + a5f1c3f commit 37acd37
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 61 deletions.
41 changes: 41 additions & 0 deletions .github/.gitmessage.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[#issue] type: description

# Commit Message Convention
#
# - 커밋 메시지는 반드시 영어로 작성합니다.
# - GitHub 이슈 번호를 참조합니다.
# - Description의 첫 글자는 대문자로 시작합니다.
#
# 기본 형식
# - `[#{issue-number}] <type>: <description>`
#
# 예시
# - `[#123] feat: Add login functionality`
#
# Commit Types
#
# 🌟 새로운 기능 및 주요 변경
# - `feat`: 새로운 기능 추가
# - `!BREAKING CHANGE`: 큰 API 변경
#
# 🛠️ 버그 수정 및 긴급 조치
# - `fix`: 버그 수정
# - `!HOTFIX`: 긴급한 버그 수정
#
# 🔧 코드 개선
# - `refactor`: 코드 리팩토링
# - `style`: 코드 포맷 변경, 세미콜론 누락 등 코드 수정 없는 경우
#
# 📚 문서 및 주석
# - `docs`: 문서 수정
# - `comment`: 주석 추가 및 변경
#
# 🧪 테스트
# - `test`: 테스트 코드 추가, 프로덕션 코드 변경 없음
#
# 🏗️ 구조적 변경
# - `rename`: 파일/폴더명 수정, 이동
# - `remove`: 파일 삭제
#
# 🎨 기타
# - `chore`: 빌드 업무 수정, 패키지 매니저 변경 등 프로덕션 코드 변경 없는 경우
98 changes: 96 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

# yml
**/application-local.yml
**/application-prod.yml
**/application-test.yml

# db data
data/
### IntelliJ IDEA ###
.idea
*.iws
Expand All @@ -18,4 +19,97 @@ out/
!**/src/main/**/out/
!**/src/test/**/out/

### Database ###
*.accdb
*.db
*.dbf
*.mdb
*.pdb
*.sqlite3
*.db-shm
*.db-wal

### Java ###
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### macOS Patch ###
# iCloud generated files
*.icloud

### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# JDK 17을 기반으로 하는 이미지 사용
FROM openjdk:17-alpine

# 작업 디렉토리
WORKDIR /usr/src/app

# 변수 정의 (빌드 시 사용)
ARG JAR_PATH=./build/libs

# 빌드한 파일 옮기기
COPY ${JAR_PATH}/*.jar ${JAR_PATH}/app.jar

# 환경변수 설정 (실행중인 컨테이너에 액세스 가능)
ENV JAR_PATH ${JAR_PATH}

# ENV 이용해서 실행
CMD java -jar ${JAR_PATH}/app.jar
66 changes: 35 additions & 31 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,55 +1,59 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
id "org.sonarqube" version "4.0.0.2929"
id 'java'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
id "org.sonarqube" version "4.0.0.2929"
}

group = 'org.dnd'
version = '0.0.1-SNAPSHOT'

java {
sourceCompatibility = '17'
sourceCompatibility = '17'
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'com.h2database:h2'

// third-party
implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
implementation("org.springframework.boot:spring-boot-devtools")


compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
runtimeOnly("com.h2database:h2")

annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'com.h2database:h2'

// third-party
implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0'

}

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

sonar {
properties {
property "sonar.projectKey", "dnd-10th-2-backend"
}
properties {
property "sonar.projectKey", "dnd-10th-2-backend"
}
}
18 changes: 18 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: '3.7'
services:
app:
build:
context: .
dockerfile: Dockerfile
environment: # 환경 변수 설정
- SPRING_DATASOURCE_URL=jdbc:h2:file:/usr/src/app/data/mydb;DB_CLOSE_ON_EXIT=FALSE
platform: linux/amd64
ports:
- "8080:8080"
# h2data 볼륨을 컨테이너 내부의 /usr/src/app/data에 매핑
volumes:
- h2data:/usr/src/app/data

# 볼륨 정의 (기본 설정 사용)
volumes:
h2data:
54 changes: 31 additions & 23 deletions src/main/java/org/dnd/modutimer/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package org.dnd.modutimer.config;


import java.util.Collections;
import org.dnd.modutimer.common.exception.ForbiddenError;
import org.dnd.modutimer.common.security.CustomAuthenticationEntryPoint;
import org.dnd.modutimer.common.security.JwtAuthenticationFilter;
import org.dnd.modutimer.utils.FilterResponseUtils;
import org.dnd.modutimer.user.application.UserFindService;
import org.dnd.modutimer.utils.FilterResponseUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
Expand All @@ -27,8 +28,6 @@
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Collections;


@Configuration
@EnableWebSecurity
Expand All @@ -44,16 +43,20 @@ public class SecurityConfig {
private UserFindService userUtilityService;

public static final String[] PUBLIC_URLS = {
// swaggger url
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-resources/**",
// open url
"/api/v1/users/**",
// swaggger url
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-resources/**",
// open url
"/api/v1/users/**",
//h2-console
"/h2-console/**"

};

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}

Expand All @@ -68,19 +71,22 @@ public CustomAuthenticationEntryPoint authenticationEntryPoint() {
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager)
throws Exception {
// CSRF 해제
http.csrf(csrf -> csrf.disable());

// iframe 거부
// iframe 허용 : h2-console 사용 목적
http.headers(headers -> headers
.contentSecurityPolicy(csp -> csp.policyDirectives("frame-ancestors 'none'")));
.frameOptions(frameOptions -> frameOptions.disable())
);

// cors 재설정
http.cors(cors -> cors.configurationSource(configurationSource()));

// jSessionId 사용 거부 (토큰 인증 방식 사용)
http.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

// form 로그인 해제 (UsernamePasswordAuthenticationFilter 비활성화)
http.formLogin(form -> form.disable());
Expand All @@ -89,23 +95,25 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http, Authentication
http.httpBasic(httpBasic -> httpBasic.disable());

// JwtAuthenticationFilter 추가
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager, userUtilityService);
JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager,
userUtilityService);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

// 인증 실패, 권한 실패 처리
http.exceptionHandling(exception -> exception
.authenticationEntryPoint(authenticationEntryPoint()) // 인증 실패 처리
.accessDeniedHandler(((request, response, accessDeniedException) -> {
// 접근 거부 처리
FilterResponseUtils.forbidden(response, new ForbiddenError(
ForbiddenError.ErrorCode.ROLE_BASED_ACCESS_ERROR,
Collections.singletonMap("access", "Access is denied")
));
})));
.authenticationEntryPoint(authenticationEntryPoint()) // 인증 실패 처리
.accessDeniedHandler(((request, response, accessDeniedException) -> {
// 접근 거부 처리
FilterResponseUtils.forbidden(response, new ForbiddenError(
ForbiddenError.ErrorCode.ROLE_BASED_ACCESS_ERROR,
Collections.singletonMap("access", "Access is denied")
));
})));

// 인증, 권한 필터 설정
http.authorizeHttpRequests(auth -> auth
.requestMatchers(PUBLIC_URLS).permitAll() // 인증 없이 접근 허용

// .anyRequest().authenticated()
.anyRequest().authenticated()
);
Expand Down
Loading

0 comments on commit 37acd37

Please sign in to comment.