Skip to content

Commit

Permalink
Merge pull request #8 from HwiYul-G/07-CICD
Browse files Browse the repository at this point in the history
CICD 테스트 - deploy할 때 webapp 이름 명세 + repo 명세 -> CD 촉발
  • Loading branch information
HwiYul-G authored Apr 27, 2024
2 parents bb5dc14 + 7f1ce27 commit a8c0430
Show file tree
Hide file tree
Showing 58 changed files with 2,219 additions and 11 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/azure-webapps-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Build and deploy a container to an Azure Web App

env:
AZURE_WEBAPP_NAME: java-board

on:
push:
branches:
- main

permissions:
contents: 'read'
packages: 'write'

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Check out the repository
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: 'maven'
- name: Build with Maven
run: mvn --batch-mode --update-snapshots package -DskipTests
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: java-board-webapp
run: echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}
- name: Build and push container image to registry
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ env.REPO }}:${{ github.sha }}
file: ./Dockerfile

deploy:
runs-on: ubuntu-latest
needs: build
steps:
- name: java_board
run: echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV}
- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
images: 'ghcr.io/${{ env.REPO }}:${{ github.sha }}'
- name: Check deployment status # deployment가 fail했을 때 main 브랜치로 push되는 것을 막기
if: ${{ failure() }}
run: exit 1
- name: Prevent push to main branch on deployment failure
if: ${{ failure() }}
run: git reset --hard HEAD^
22 changes: 22 additions & 0 deletions .github/workflows/maven-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Java CI with Maven

on:
pull_request:
branches: ["main"]

jobs:
build:

runs-on: ubuntu-latest

steps:
- name: Check out the repository
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Build and test with Maven
run: mvn --batch-mode package
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM eclipse-temurin:17-jre as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM eclipse-temurin:17-jre
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
71 changes: 66 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,69 @@
## 사용 라이브러리
- data-jpa : spring-data-jpa로 손쉽게 datsource에 접근 하기 위함
- thymeleaf :
- bootstrap
- devtools : 재시작 없이 하려고
- mysql : 데이터베이스
- lombok : @Getter, @Setter 등 간편하게 하려고
- mockito-core : unit test를 위해 mock 객체 생성용
## 기능 구현 목록
### Article
- [] id, title, content, createdAt, updatedAt, writer
- [] 작성하기(Create)
- [] 개별 조회하기(retrieve)
- [] 목록 조회하기
- [x] id, title, content, createdAt, updatedAt, writer
- [x] comments
- [x] 작성하기(Create)
- [x] writer의 값으로 User의 nickname을 넣는다.
- [x] 개별 조회하기(retrieve)
- [x] 목록 조회하기
- [x] 페이징 적용
- [x] 수정하기(update)
- [x] 작성한 User만 수정이 가능하게 한다.
- [x] 이를 위해선 사용자 nickname(writer)가 중복이 안 되게 해야한다.
- [x] 이를 위해 nicknme 기반으로 email 찾기 기능 추가
- [x] 삭제하기(delete)
- [x] 작성한 User만 삭제가 가능하게 한다.
- [x] 관련된 comment를 먼저 지우고 현재 게시글이 지워지게 한다.
- [x] comments 가져오기
### Comment
- [x] id, content, createdAt, updatedAt, article(owner)
- [x] 작성하기(create)
- [x] writer의 값으로 User의 nickname을 넣는다.
- [x] 삭제하기(delete)
- [x] 작성한 사용자만 수정가능하게 한다.
- 이를 위해 `customAuthenticationSuccessHandler``CustomLogoutSuccessHandler`를 만들고 `SecurityConfig`의 필터체인에 등록해준다.
- 사용 하고 자 하는 부분인 ArticleController에 `@SessionAttributes(key)`로 등록한 세션을 접근가능하게 만든다.
- 필요한 get 함수에서 Model을 통해 view로 보내준다.
- view에서 작성한 사용자의 nickname 기반으로 게시글의 writer와 현재 로그인한 사용자의 nickname이 일치하지 않으면 삭제, 수정 버튼이 보이지 않게 한다.
- [x] 수정하기(update)
- [x] 삭제하기와 마찬가지로 작성한 사용자만 수정가능 하게 한다.
### User
- [x] id, nickname, email, password, name
- [x] 등록하기(register)
- [] 수정하기(update)
- [] 삭제하기(delete)
- [x] password수정
- 데이터베이스에 저장된 그 비밀번호와 비교할 수 있어야 한다.
- 올바른 비밀번호를 입력해도 비교가 제대로 안 되는 문제가 있었다.
- 이는 비밀번호를 encode해서 입력될 때 같은 값이여도 다르게 되는 문제 때문이다. (random salt사용)
- 정확히 authentication context의 것을 가져와서 수행한다.
- [] email 수정
- 세션에 등록된 email도 변경 되게 해야 한다.
- [x] 이미지 수정
- [x] nickname 수정
- 닉네임 수정시 현재 사용자가 만든 article과 작성한 comment에 대한 닉네임을 모두 변경
- 세션에 등록된 닉네임도 변경
- [x] 탈퇴하기(delete)
- [x] 사용자의 저장된 프로필 이미지를 삭제한다.
- [x] 사용자의 댓글을 전부 삭제 한다.
- [x] 사용자가 작성했던 게시글을 전부 삭제한다.
- [x] 내가 쓴 게시글 목록 보기
- [x] 페이징 처리
- [x] 게시글의 다른 페이지를 클랙해도 기존 댓글 페이지는 유지하기
- [x] 게시글 삭제 후, 개인정보 페이지에 있게 하기
- [x] 게시글 보기에서 뒤로가기 버튼 클릭시, 개인정보 페이지에 있게 하기
- [x] 사용자 정보에서 게시글 보기를 들어가서 아래 행위 후, 뒤로가기 버튼을 누르면 개인정보가 아니라 게시판 있던 부분으로 가지는 문제
- [x] 새 댓글 작성
- [x] 댓글 수정
- [x] 댓글 삭제
- [x] 게시글 수정
- [x] 게시글 삭제
- [x] 내가 쓴 댓글 보기, paging 처리
- [x] 댓글의 다른 페이지를 클릭해도 기존 게시글 페이지는 유지하기
60 changes: 54 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,81 @@
<java.version>17</java.version>
</properties>
<dependencies>
<!-- persistence -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- <dependency>-->
<!-- <groupId>com.mysql</groupId>-->
<!-- <artifactId>mysql-connector-j</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>5.1.3</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

<!-- security -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
</dependency>


<!-- useful -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

</dependencies>

<build>
Expand Down
81 changes: 81 additions & 0 deletions src/main/java/com/y/java_board/config/SpringSecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.y.java_board.config;

import com.y.java_board.config.security.CustomAuthenticationSuccessHandler;
import com.y.java_board.config.security.CustomLogoutSuccessHandler;
import com.y.java_board.config.security.CustomUserDetailsService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HttpBasicConfigurer;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
@AllArgsConstructor
public class SpringSecurityConfig {

private final CustomUserDetailsService userDetailsService;
private final CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
private final CustomLogoutSuccessHandler customLogoutSuccessHandler;

private final Logger logger = LoggerFactory.getLogger(getClass());

@Bean
public InMemoryUserDetailsManager userDetailsManager() {
UserDetails admin = User.withUsername("admin")
.password(passwordEncoder().encode("1234"))
.roles("ADMIN")
.build();

UserDetails user1 = User.withUsername("user1")
.password(passwordEncoder().encode("1234"))
.roles("USER")
.build();

return new InMemoryUserDetailsManager(admin, user1);
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.httpBasic(HttpBasicConfigurer::disable)
.authorizeHttpRequests(auth ->
auth.requestMatchers("/", "/user/register",
"/webjars/**", "/css/**", "/js/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(login ->
login.successHandler(customAuthenticationSuccessHandler))
.logout(logout ->
logout.logoutSuccessHandler(customLogoutSuccessHandler)
.permitAll()
);
return http.build();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
public AuthenticationManager authenticationManager() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return new ProviderManager(provider);
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/y/java_board/config/UserInfoSession.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.y.java_board.config;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
@AllArgsConstructor
public class UserInfoSession {
private String email;
private String nickname;
private String profileImage;
private String name;
}
Loading

0 comments on commit a8c0430

Please sign in to comment.